takomi 2.1.32 → 2.1.34
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/.pi/extensions/oauth-router/config.ts +14 -5
- package/.pi/extensions/oauth-router/index.ts +130 -130
- package/.pi/extensions/oauth-router/provider.ts +29 -0
- package/.pi/extensions/oauth-router/state.ts +372 -372
- package/.pi/extensions/oauth-router/types.ts +1 -1
- package/.pi/extensions/takomi-runtime/command-text.ts +2 -4
- package/.pi/extensions/takomi-runtime/commands.ts +15 -21
- package/.pi/extensions/takomi-runtime/index.ts +127 -53
- package/.pi/extensions/takomi-runtime/model-routing-defaults.ts +296 -296
- package/.pi/extensions/takomi-runtime/ui.ts +18 -11
- package/.pi/extensions/takomi-subagents/index.ts +2 -0
- package/.pi/extensions/takomi-subagents/native-render.ts +27 -5
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +1 -1
- package/.pi/extensions/takomi-subagents/tool-runner.ts +1 -0
- package/assets/.agent/skills/photo-book-builder/SKILL.md +96 -0
- package/assets/.agent/skills/photo-book-builder/references/layout_templates.md +72 -0
- package/assets/.agent/skills/photo-book-builder/scripts/create_full_bleed_layouts.py +212 -0
- package/assets/.agent/skills/photo-book-builder/scripts/organize_photos.py +99 -0
- package/assets/.agent/skills/photo-book-builder/scripts/revert_organization.py +61 -0
- package/assets/.agent/skills/photo-book-builder/scripts/upscale_covers.py +47 -0
- package/assets/.agent/skills/youtube-pipeline/SKILL.md +73 -62
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Application.md +1 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Phase 1.md +86 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Phase 2.md +106 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Phase 3.md +112 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Phase 4.md +90 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Phased Outline.md +58 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Repurposing.md +1 -0
- package/assets/.agent/skills/youtube-pipeline/resources/knowledge/Research.md +438 -0
- package/assets/.agent/skills/youtube-pipeline/resources/prompts/Shorts Bridge Protocol.md +159 -0
- package/assets/.agent/skills/youtube-pipeline/resources/prompts/Title Thumbnail Picker Prompt.md +144 -0
- package/assets/.agent/skills/youtube-pipeline/resources/prompts/Transcription Extraction Prompt v2.md +190 -0
- package/assets/.agent/skills/youtube-pipeline/resources/prompts/Transcription Extraction Prompt.md +156 -0
- package/assets/.agent/skills/youtube-pipeline/resources/prompts/Video QA Prompt.md +133 -0
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-phase1-strategy.md +28 -18
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-phase2-packaging.md +2 -2
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-phase3-scripting.md +2 -2
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-phase3.5-shorts.md +2 -2
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-phase4-production.md +2 -2
- package/assets/.agent/skills/youtube-pipeline/resources/youtube-pipeline.md +15 -15
- package/assets/.agent/skills/youtube-pipeline/scripts/google-trends/package.json +17 -0
- package/assets/.agent/skills/youtube-pipeline/scripts/google-trends/pnpm-lock.yaml +31 -0
- package/assets/.agent/skills/youtube-pipeline/scripts/google-trends/search.js +168 -0
- package/package.json +1 -1
- package/src/cli.js +13 -4
- package/src/pi-harness.js +36 -14
- package/src/pi-optional-features.js +190 -190
- package/src/postinstall.js +27 -27
- package/src/skills-catalog.js +245 -245
- package/src/skills-installer.js +244 -244
- package/src/skills-selection-tui.js +200 -200
- package/src/store.js +418 -418
- package/src/takomi-stats.d.ts +3 -3
- package/src/takomi-stats.js +442 -35
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
**You are "QA Hawk" — a ruthless YouTube video quality auditor.**
|
|
2
|
+
|
|
3
|
+
Your job is to watch my video (or the intro section I provide) and tear it apart before my audience does. You are not here to be nice. You are here to catch every weakness, every boring moment, every missed opportunity.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### **WHAT I WILL PROVIDE:**
|
|
8
|
+
|
|
9
|
+
I will give you one of the following:
|
|
10
|
+
- **Full video file** (or link)
|
|
11
|
+
- **Intro clip only** (first 30-60 seconds)
|
|
12
|
+
- **Key timestamps to review**
|
|
13
|
+
- **Screenshots at specific moments**
|
|
14
|
+
|
|
15
|
+
I may also provide:
|
|
16
|
+
- The **title and thumbnail** (for consistency check)
|
|
17
|
+
- The **script** (to compare intent vs. execution)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
### **YOUR FRAMEWORK: THE 5 AUDITS**
|
|
22
|
+
|
|
23
|
+
Run the video through these 5 audits and report issues for each.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## **1. THE HOOK AUDIT (0:00 - 0:45)**
|
|
28
|
+
*Reference: Phase 3 Hook Structure*
|
|
29
|
+
|
|
30
|
+
| Check | Pass/Fail | Notes |
|
|
31
|
+
|-------|-----------|-------|
|
|
32
|
+
| **First Frame Match** — Does the first frame match the thumbnail? | | |
|
|
33
|
+
| **Scroll Stopper** — Is the first line compelling enough to stop a scroll? | | |
|
|
34
|
+
| **Stakes Clear** — Do I know what I lose by leaving within 10 seconds? | | |
|
|
35
|
+
| **Input Bias** — Is there a credibility flex ("I spent X doing Y")? | | |
|
|
36
|
+
| **Payoff Promise** — Do I know what I'll get by the end? | | |
|
|
37
|
+
| **No Wasted Time** — Is there any rambling, logos, or "hey guys" before the hook? | | |
|
|
38
|
+
|
|
39
|
+
**The 5-Second Test:** If I was scrolling YouTube, would I stop on this? Why or why not?
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## **2. THE RETENTION AUDIT (Full Video)**
|
|
44
|
+
*Reference: Phase 3 Loop Architecture + Phase 4 Dopamine Machine*
|
|
45
|
+
|
|
46
|
+
| Check | Pass/Fail | Notes |
|
|
47
|
+
|-------|-----------|-------|
|
|
48
|
+
| **Screen Change Frequency** — Does the visual change every 3-5 seconds? | | |
|
|
49
|
+
| **Pattern Interrupts** — Is there a drastic change every 45-60 seconds? | | |
|
|
50
|
+
| **Open Loops** — Are there forward hooks that make me want to keep watching? | | |
|
|
51
|
+
| **Dead Air** — Are there any gaps, pauses, or boring stretches? | | |
|
|
52
|
+
| **Mid-Video Dip** — Is there a section where I would click away? Mark the timestamp. | | |
|
|
53
|
+
| **Pacing** — Does it feel too slow, too rushed, or just right? | | |
|
|
54
|
+
|
|
55
|
+
**The Boredom Timestamp:** At what exact moment did my attention first wander? Why?
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## **3. THE VISUAL AUDIT**
|
|
60
|
+
*Reference: Phase 4 Filming Protocol + Dopamine Machine*
|
|
61
|
+
|
|
62
|
+
| Check | Pass/Fail | Notes |
|
|
63
|
+
|-------|-----------|-------|
|
|
64
|
+
| **Lighting** — Is the face well-lit without harsh shadows? | | |
|
|
65
|
+
| **Audio** — Is it clean, clear, and close? Any echo or distortion? | | |
|
|
66
|
+
| **Eye Contact** — Does the speaker maintain lens lock? | | |
|
|
67
|
+
| **Energy** — Is the delivery 110% or does it feel flat? | | |
|
|
68
|
+
| **B-Roll Quality** — Is the B-roll relevant and high quality? | | |
|
|
69
|
+
| **Text/Graphics** — Are they clean, readable, and not overwhelming? | | |
|
|
70
|
+
| **Thumbnail Consistency** — Does the video match the thumbnail promise? | | |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## **4. THE TITLE/THUMBNAIL SYNC AUDIT**
|
|
75
|
+
*Reference: Phase 2 Synergy Check*
|
|
76
|
+
|
|
77
|
+
| Check | Pass/Fail | Notes |
|
|
78
|
+
|-------|-----------|-------|
|
|
79
|
+
| **Title Delivered** — Does the video actually deliver on the title promise? | | |
|
|
80
|
+
| **Thumbnail Payoff** — Is the thumbnail moment in the video? | | |
|
|
81
|
+
| **No Bait-and-Switch** — Would a viewer feel misled? | | |
|
|
82
|
+
| **Curiosity Closed** — Is the curiosity gap from the title fully answered? | | |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## **5. THE OUTRO AUDIT**
|
|
87
|
+
*Reference: Phase 3 Outro Strategy*
|
|
88
|
+
|
|
89
|
+
| Check | Pass/Fail | Notes |
|
|
90
|
+
|-------|-----------|-------|
|
|
91
|
+
| **No Signal Words** — Did I say "in conclusion," "that's it," or "thanks for watching"? | | |
|
|
92
|
+
| **Bridge to Next Video** — Is there a clear CTA to a specific next video? | | |
|
|
93
|
+
| **Open Loop Forward** — Does the outro create curiosity for the next video? | | |
|
|
94
|
+
| **Hard vs. Soft CTA** — Which was used and was it appropriate? | | |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### **OUTPUT FORMAT**
|
|
99
|
+
|
|
100
|
+
After auditing, provide:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
🔴 CRITICAL ISSUES (Fix before upload)
|
|
104
|
+
- [Issue 1]
|
|
105
|
+
- [Issue 2]
|
|
106
|
+
|
|
107
|
+
🟡 WARNINGS (Should fix, but not fatal)
|
|
108
|
+
- [Issue 1]
|
|
109
|
+
- [Issue 2]
|
|
110
|
+
|
|
111
|
+
🟢 WINS (What's working well)
|
|
112
|
+
- [Strength 1]
|
|
113
|
+
- [Strength 2]
|
|
114
|
+
|
|
115
|
+
📍 BOREDOM TIMESTAMPS
|
|
116
|
+
- [Timestamp 1]: [Why attention dropped]
|
|
117
|
+
- [Timestamp 2]: [Why attention dropped]
|
|
118
|
+
|
|
119
|
+
🎯 FINAL VERDICT
|
|
120
|
+
[SHIP IT / NEEDS WORK / DO NOT UPLOAD]
|
|
121
|
+
|
|
122
|
+
Reason: [One sentence summary]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### **ATTITUDE REMINDER**
|
|
128
|
+
|
|
129
|
+
You are not my friend. You are my harshest critic. If the video is mid, say it's mid. If the intro is boring, say it's boring. If the hook is weak, roast it.
|
|
130
|
+
|
|
131
|
+
Better I hear it from you than from the comments section.
|
|
132
|
+
|
|
133
|
+
**NOW PROVIDE THE VIDEO/CLIP TO AUDIT:**
|
|
@@ -7,9 +7,9 @@ description: Phase 1 of YouTube Pipeline - The Strategy Engine (Ideation & Resea
|
|
|
7
7
|
> **Your Role**: You are a brutal expert YouTube strategist. You generate ideas, challenge weak concepts, and demand proof. You teach the "why" behind every step. Never yes-man.
|
|
8
8
|
|
|
9
9
|
## Step 0: Load Source Knowledge
|
|
10
|
-
Before starting, read the full phase document to get undiluted context:
|
|
10
|
+
Before starting, read the full phase document to get undiluted context (packaged locally):
|
|
11
11
|
```
|
|
12
|
-
View file:
|
|
12
|
+
View file: knowledge/Phase 1.md
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Step 1: Gather Context
|
|
@@ -19,7 +19,7 @@ Ask the user:
|
|
|
19
19
|
3. **Target Audience**: "Who exactly watches you? Age, situation, pain points?"
|
|
20
20
|
4. **Mode**: "Do you want me to drive (Guided) or do you want more control (Manual)?"
|
|
21
21
|
|
|
22
|
-
If user
|
|
22
|
+
If the user provides prior notes, summaries, or project context, use them to pre-fill answers. Do not depend on a private vault path.
|
|
23
23
|
|
|
24
24
|
## Step 2: The Outlier Hunt (AI-Driven)
|
|
25
25
|
Based on their niche, **you generate** potential outlier directions:
|
|
@@ -67,10 +67,11 @@ Guide the user through this process to extract bulk data:
|
|
|
67
67
|
4. **User Action**: Right-click → Copy → Copy outerHTML
|
|
68
68
|
5. **User Action**: Paste into a `.html` file (e.g., `ai_coding.html`)
|
|
69
69
|
6. **Agent Action**: Parse the file:
|
|
70
|
-
```powershell
|
|
71
|
-
# Parse YouTube Studio HTML export
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
```powershell
|
|
71
|
+
# Parse YouTube Studio HTML export
|
|
72
|
+
$SkillRoot = "<path-to-installed-youtube-pipeline-skill>"
|
|
73
|
+
powershell -ExecutionPolicy Bypass -File (Join-Path $SkillRoot "scripts/parse_yt_studio.ps1") -InputFile "ai_coding.html" -OutputFile "parsed_topics.md"
|
|
74
|
+
```
|
|
74
75
|
|
|
75
76
|
**Repeat for each topic category** (e.g., "Claude AI", "VibeCoding", "Design System") to build comprehensive demand data.
|
|
76
77
|
|
|
@@ -118,17 +119,26 @@ Ask them to go to their top 3 outlier videos and pull:
|
|
|
118
119
|
### 4b. Google Trends Deep Dive
|
|
119
120
|
Don't just glance at a trend line. Use Google Trends properly:
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
Use the
|
|
123
|
-
```powershell
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
**Automated Method (Bundled CLI):**
|
|
123
|
+
Use the packaged Google Trends CLI in this skill:
|
|
124
|
+
```powershell
|
|
125
|
+
# First-time dependency install
|
|
126
|
+
$SkillRoot = "<path-to-installed-youtube-pipeline-skill>"
|
|
127
|
+
$TrendRoot = Join-Path $SkillRoot "scripts/google-trends"
|
|
128
|
+
Push-Location $TrendRoot
|
|
129
|
+
pnpm install
|
|
130
|
+
Pop-Location
|
|
131
|
+
|
|
132
|
+
# Search YouTube trends for a keyword
|
|
133
|
+
node (Join-Path $SkillRoot "scripts/google-trends/search.js") -k "Claude Cowork" -p youtube -t "now 7-d" -o table
|
|
134
|
+
|
|
135
|
+
# Search multiple keywords
|
|
136
|
+
node (Join-Path $SkillRoot "scripts/google-trends/search.js") -k "Vibe Coding" -p youtube
|
|
137
|
+
node (Join-Path $SkillRoot "scripts/google-trends/search.js") -k "AI coding" -p youtube
|
|
138
|
+
node (Join-Path $SkillRoot "scripts/google-trends/search.js") -k "Cursor IDE" -p youtube
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Do not assume a specific install root such as `~/.gemini`, `~/.codex`, `~/.agents`, or any private project folder. If Node dependencies are unavailable, use the manual method below.
|
|
132
142
|
|
|
133
143
|
**Key Signals:**
|
|
134
144
|
- `BREAKOUT` = 5000%+ growth = **GOLD**
|
|
@@ -7,9 +7,9 @@ description: Phase 2 of YouTube Pipeline - The Packaging Lab (Title & Thumbnail)
|
|
|
7
7
|
> **Your Role**: You are a brutal expert YouTube strategist. You generate titles and thumbnail concepts. You critique ruthlessly. The packaging MUST be irresistible before we move to scripting.
|
|
8
8
|
|
|
9
9
|
## Step 0: Load Source Knowledge
|
|
10
|
-
Before starting, read the full phase document:
|
|
10
|
+
Before starting, read the full phase document (packaged locally):
|
|
11
11
|
```
|
|
12
|
-
View file:
|
|
12
|
+
View file: knowledge/Phase 2.md
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Also recall the Phase 1 output:
|
|
@@ -7,9 +7,9 @@ description: Phase 3 of YouTube Pipeline - The Scripting Forge (Retention & Psyc
|
|
|
7
7
|
> **Your Role**: You are a brutal expert YouTube scriptwriter. You draft hooks, structure loops, and write copy. Every sentence must build tension, provide value, or move the story forward. If it does neither, delete it.
|
|
8
8
|
|
|
9
9
|
## Step 0: Load Source Knowledge
|
|
10
|
-
Before starting, read the full phase document:
|
|
10
|
+
Before starting, read the full phase document (packaged locally):
|
|
11
11
|
```
|
|
12
|
-
View file:
|
|
12
|
+
View file: knowledge/Phase 3.md
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Also recall Phase 1 & 2 outputs:
|
|
@@ -16,9 +16,9 @@ Run this **after Phase 3 (Scripting)** is complete, or during Phase 3 if you wan
|
|
|
16
16
|
|
|
17
17
|
## Step 0: Load Source Knowledge
|
|
18
18
|
|
|
19
|
-
Read the Phase 3 source document to get the full scripting framework:
|
|
19
|
+
Read the Phase 3 source document to get the full scripting framework (packaged locally):
|
|
20
20
|
```
|
|
21
|
-
View file:
|
|
21
|
+
View file: knowledge/Phase 3.md
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
This gives you access to:
|
|
@@ -7,9 +7,9 @@ description: Phase 4 of YouTube Pipeline - Production & Post-Production. Film, e
|
|
|
7
7
|
> **Your Role**: You are a brutal expert video producer. You create filming checklists, editing guides, and quality control passes. The script provides value; the edit provides dopamine.
|
|
8
8
|
|
|
9
9
|
## Step 0: Load Source Knowledge
|
|
10
|
-
Before starting, read the full phase document:
|
|
10
|
+
Before starting, read the full phase document (packaged locally):
|
|
11
11
|
```
|
|
12
|
-
View file:
|
|
12
|
+
View file: knowledge/Phase 4.md
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Also recall all previous outputs:
|
|
@@ -124,21 +124,21 @@ Status: FULLY DISTRIBUTED
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
126
|
## Phase Workflow References
|
|
127
|
-
Each phase has its own detailed workflow:
|
|
128
|
-
- Phase 1: `
|
|
129
|
-
- Phase 2: `
|
|
130
|
-
- Phase 3: `
|
|
131
|
-
- Phase 3.5: `
|
|
132
|
-
- Phase 4: `
|
|
133
|
-
- Phase 5: `
|
|
134
|
-
|
|
135
|
-
Each workflow also reads from source knowledge:
|
|
136
|
-
- Source 1: `
|
|
137
|
-
- Source 2: `
|
|
138
|
-
- Source 3: `
|
|
139
|
-
- Source 4: `
|
|
140
|
-
- Research: `
|
|
141
|
-
- Repurposing: `
|
|
127
|
+
Each phase has its own detailed workflow (packaged locally):
|
|
128
|
+
- Phase 1: `youtube-phase1-strategy.md`
|
|
129
|
+
- Phase 2: `youtube-phase2-packaging.md`
|
|
130
|
+
- Phase 3: `youtube-phase3-scripting.md`
|
|
131
|
+
- Phase 3.5: `youtube-phase3.5-shorts.md`
|
|
132
|
+
- Phase 4: `youtube-phase4-production.md`
|
|
133
|
+
- Phase 5: `youtube-phase5-repurposing.md`
|
|
134
|
+
|
|
135
|
+
Each workflow also reads from local source knowledge:
|
|
136
|
+
- Source 1: `knowledge/Phase 1.md`
|
|
137
|
+
- Source 2: `knowledge/Phase 2.md`
|
|
138
|
+
- Source 3: `knowledge/Phase 3.md`
|
|
139
|
+
- Source 4: `knowledge/Phase 4.md`
|
|
140
|
+
- Research: `knowledge/Research.md`
|
|
141
|
+
- Repurposing: `knowledge/Repurposing.md`
|
|
142
142
|
|
|
143
143
|
---
|
|
144
144
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "google-trends-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI for Google Trends research automation",
|
|
5
|
+
"main": "search.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"search": "node search.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": ["google-trends", "youtube", "research"],
|
|
11
|
+
"author": "J STAR FILMS",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"commander": "^12.0.0",
|
|
15
|
+
"google-trends-api": "^4.9.2"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
lockfileVersion: '9.0'
|
|
2
|
+
|
|
3
|
+
settings:
|
|
4
|
+
autoInstallPeers: true
|
|
5
|
+
excludeLinksFromLockfile: false
|
|
6
|
+
|
|
7
|
+
importers:
|
|
8
|
+
|
|
9
|
+
.:
|
|
10
|
+
dependencies:
|
|
11
|
+
commander:
|
|
12
|
+
specifier: ^12.0.0
|
|
13
|
+
version: 12.1.0
|
|
14
|
+
google-trends-api:
|
|
15
|
+
specifier: ^4.9.2
|
|
16
|
+
version: 4.9.2
|
|
17
|
+
|
|
18
|
+
packages:
|
|
19
|
+
|
|
20
|
+
commander@12.1.0:
|
|
21
|
+
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
|
22
|
+
engines: {node: '>=18'}
|
|
23
|
+
|
|
24
|
+
google-trends-api@4.9.2:
|
|
25
|
+
resolution: {integrity: sha512-gjVSHCM8B7LyAAUpXb4B0/TfnmpwQ2z1w/mQ2bL0AKpr2j3gLS1j2YOnifpfsGJRxAGXB/NoC+nGwC5qSnZIiA==}
|
|
26
|
+
|
|
27
|
+
snapshots:
|
|
28
|
+
|
|
29
|
+
commander@12.1.0: {}
|
|
30
|
+
|
|
31
|
+
google-trends-api@4.9.2: {}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import googleTrends from 'google-trends-api';
|
|
4
|
+
|
|
5
|
+
program
|
|
6
|
+
.name('search')
|
|
7
|
+
.description('Google Trends CLI for topic research')
|
|
8
|
+
.requiredOption('-k, --keyword <string>', 'Topic to search')
|
|
9
|
+
.option('-p, --property <string>', 'youtube | web | images | news | froogle', 'youtube')
|
|
10
|
+
.option('-t, --time <string>', 'Time range (now 7-d, now 1-m, today 3-m, today 12-m)', 'now 7-d')
|
|
11
|
+
.option('-c, --category <number>', 'Category ID (5 = Tech)', '5')
|
|
12
|
+
.option('-o, --output <string>', 'Output format: table | json | markdown', 'table')
|
|
13
|
+
.option('-f, --file <path>', 'Output file path')
|
|
14
|
+
.option('--interest', 'Include interest-over-time data', false)
|
|
15
|
+
.parse();
|
|
16
|
+
|
|
17
|
+
const opts = program.opts();
|
|
18
|
+
|
|
19
|
+
// Parse time range string to date
|
|
20
|
+
function getStartTime(timeStr) {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
const match = timeStr.match(/^(now|today)\s+(\d+)-([dmy])$/);
|
|
23
|
+
if (!match) return new Date(now - 7 * 24 * 60 * 60 * 1000); // default 7 days
|
|
24
|
+
|
|
25
|
+
const [, , num, unit] = match;
|
|
26
|
+
const amount = parseInt(num, 10);
|
|
27
|
+
switch (unit) {
|
|
28
|
+
case 'd': return new Date(now - amount * 24 * 60 * 60 * 1000);
|
|
29
|
+
case 'm': return new Date(now - amount * 30 * 24 * 60 * 60 * 1000);
|
|
30
|
+
case 'y': return new Date(now - amount * 365 * 24 * 60 * 60 * 1000);
|
|
31
|
+
default: return new Date(now - 7 * 24 * 60 * 60 * 1000);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function fetchRelatedQueries() {
|
|
36
|
+
const result = await googleTrends.relatedQueries({
|
|
37
|
+
keyword: opts.keyword,
|
|
38
|
+
startTime: getStartTime(opts.time),
|
|
39
|
+
property: opts.property === 'web' ? '' : opts.property,
|
|
40
|
+
category: parseInt(opts.category, 10),
|
|
41
|
+
});
|
|
42
|
+
return JSON.parse(result);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function fetchInterestOverTime() {
|
|
46
|
+
if (!opts.interest) return null;
|
|
47
|
+
const result = await googleTrends.interestOverTime({
|
|
48
|
+
keyword: opts.keyword,
|
|
49
|
+
startTime: getStartTime(opts.time),
|
|
50
|
+
property: opts.property === 'web' ? '' : opts.property,
|
|
51
|
+
category: parseInt(opts.category, 10),
|
|
52
|
+
});
|
|
53
|
+
return JSON.parse(result);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatTable(data, interest) {
|
|
57
|
+
const lines = [];
|
|
58
|
+
lines.push(`\n[TrendProbe] Searching: "${opts.keyword}" on ${opts.property} (${opts.time})\n`);
|
|
59
|
+
|
|
60
|
+
const ranked = data?.default?.rankedList || [];
|
|
61
|
+
ranked.forEach((list, idx) => {
|
|
62
|
+
const label = idx === 0 ? 'Top' : 'Rising';
|
|
63
|
+
lines.push(`--- Related Queries (${label}) ---`);
|
|
64
|
+
|
|
65
|
+
(list.rankedKeyword || []).forEach((item, i) => {
|
|
66
|
+
const value = typeof item.value === 'string' ? item.value : item.value;
|
|
67
|
+
const display = item.formattedValue || (value === 'Breakout' ? 'BREAKOUT' : value);
|
|
68
|
+
lines.push(`${i + 1}. ${item.query} (${display})`);
|
|
69
|
+
});
|
|
70
|
+
lines.push('');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (interest?.default?.timelineData) {
|
|
74
|
+
lines.push('--- Interest Over Time ---');
|
|
75
|
+
const timeline = interest.default.timelineData.slice(-7); // Last 7 data points
|
|
76
|
+
timeline.forEach(point => {
|
|
77
|
+
lines.push(`${point.formattedTime}: ${point.value[0]}`);
|
|
78
|
+
});
|
|
79
|
+
lines.push('');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return lines.join('\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function formatJSON(data, interest) {
|
|
86
|
+
const ranked = data?.default?.rankedList || [];
|
|
87
|
+
const result = {
|
|
88
|
+
keyword: opts.keyword,
|
|
89
|
+
property: opts.property,
|
|
90
|
+
time: opts.time,
|
|
91
|
+
category: opts.category,
|
|
92
|
+
top: (ranked[0]?.rankedKeyword || []).map(q => ({ query: q.query, value: q.value })),
|
|
93
|
+
rising: (ranked[1]?.rankedKeyword || []).map(q => ({ query: q.query, value: q.formattedValue || q.value })),
|
|
94
|
+
};
|
|
95
|
+
if (interest?.default?.timelineData) {
|
|
96
|
+
result.interest = interest.default.timelineData.map(p => ({ time: p.formattedTime, value: p.value[0] }));
|
|
97
|
+
}
|
|
98
|
+
return JSON.stringify(result, null, 2);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function formatMarkdown(data, interest) {
|
|
102
|
+
const lines = [];
|
|
103
|
+
lines.push(`## ${opts.keyword} (${opts.property}, ${opts.time})`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
|
|
106
|
+
const ranked = data?.default?.rankedList || [];
|
|
107
|
+
if (ranked[0]?.rankedKeyword?.length) {
|
|
108
|
+
lines.push('### Top Queries');
|
|
109
|
+
ranked[0].rankedKeyword.forEach((q, i) => {
|
|
110
|
+
lines.push(`${i + 1}. ${q.query} (${q.value})`);
|
|
111
|
+
});
|
|
112
|
+
lines.push('');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (ranked[1]?.rankedKeyword?.length) {
|
|
116
|
+
lines.push('### Rising Queries');
|
|
117
|
+
ranked[1].rankedKeyword.forEach((q, i) => {
|
|
118
|
+
const display = q.formattedValue || q.value;
|
|
119
|
+
lines.push(`${i + 1}. ${q.query} (${display})`);
|
|
120
|
+
});
|
|
121
|
+
lines.push('');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (interest?.default?.timelineData) {
|
|
125
|
+
lines.push('### Interest Over Time');
|
|
126
|
+
interest.default.timelineData.slice(-7).forEach(p => {
|
|
127
|
+
lines.push(`- ${p.formattedTime}: ${p.value[0]}`);
|
|
128
|
+
});
|
|
129
|
+
lines.push('');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return lines.join('\n');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function main() {
|
|
136
|
+
try {
|
|
137
|
+
const [relatedData, interestData] = await Promise.all([
|
|
138
|
+
fetchRelatedQueries(),
|
|
139
|
+
fetchInterestOverTime(),
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
let output;
|
|
143
|
+
switch (opts.output) {
|
|
144
|
+
case 'json':
|
|
145
|
+
output = formatJSON(relatedData, interestData);
|
|
146
|
+
break;
|
|
147
|
+
case 'markdown':
|
|
148
|
+
output = formatMarkdown(relatedData, interestData);
|
|
149
|
+
break;
|
|
150
|
+
default:
|
|
151
|
+
output = formatTable(relatedData, interestData);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(output);
|
|
155
|
+
|
|
156
|
+
if (opts.file) {
|
|
157
|
+
const fs = await import('fs');
|
|
158
|
+
fs.writeFileSync(opts.file, output, 'utf-8');
|
|
159
|
+
console.log(`\n[Saved to ${opts.file}]`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
} catch (err) {
|
|
163
|
+
console.error('[Error]', err.message);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "takomi",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.34",
|
|
4
4
|
"description": "🎯 Stop wrestling with AI. Start building with purpose. The artisan's toolkit for agent workflows, Codex skills, and original Takomi capabilities like 21st.dev integration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli.js
CHANGED
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
isStoreInitialized,
|
|
44
44
|
} from './store.js';
|
|
45
45
|
import { runDoctor } from './doctor.js';
|
|
46
|
-
import { ensurePiInstalled, ensurePiSubagentsInstalled, launchTakomiHarness, printPiInstallResult, printPiSubagentsInstallResult, updatePiManagedPackages, printPiManagedPackageUpdateResult } from './pi-harness.js';
|
|
46
|
+
import { ensurePiInstalled, ensurePiSubagentsInstalled, launchTakomiHarness, printPiInstallResult, printPiSubagentsInstallResult, updatePiCliPackage, updatePiManagedPackages, printPiManagedPackageUpdateResult } from './pi-harness.js';
|
|
47
47
|
import { installPiHarnessAssets, printPiInstallSummary, syncPiHarnessAssets, validatePiHarnessInstall } from './pi-installer.js';
|
|
48
48
|
import { offerPiOptionalFeatures } from './pi-optional-features.js';
|
|
49
49
|
import {
|
|
@@ -459,7 +459,7 @@ async function installPiTarget(options = {}) {
|
|
|
459
459
|
console.log(pc.cyan('\n🧩 Optional Takomi Pi feature packs...\n'));
|
|
460
460
|
await offerPiOptionalFeatures({ interactive: true });
|
|
461
461
|
}
|
|
462
|
-
console.log(pc.cyan('\n📦 Checking Pi-managed package updates...\n'));
|
|
462
|
+
console.log(pc.cyan('\n📦 Checking Pi-managed extension package updates...\n'));
|
|
463
463
|
printPiManagedPackageUpdateResult(await updatePiManagedPackages());
|
|
464
464
|
console.log(pc.dim('\nNext: cd <project> && takomi\n'));
|
|
465
465
|
} catch (error) {
|
|
@@ -474,7 +474,7 @@ async function installPiOptionalFeaturesTarget() {
|
|
|
474
474
|
printPiInstallResult(pi);
|
|
475
475
|
if (!pi.ok) return;
|
|
476
476
|
await offerPiOptionalFeatures({ interactive: true });
|
|
477
|
-
console.log(pc.cyan('\n📦 Checking Pi-managed package updates...\n'));
|
|
477
|
+
console.log(pc.cyan('\n📦 Checking Pi-managed extension package updates...\n'));
|
|
478
478
|
printPiManagedPackageUpdateResult(await updatePiManagedPackages());
|
|
479
479
|
}
|
|
480
480
|
|
|
@@ -484,7 +484,7 @@ async function syncPiTarget() {
|
|
|
484
484
|
const result = await syncPiHarnessAssets(program.version());
|
|
485
485
|
const validation = await validatePiHarnessInstall();
|
|
486
486
|
printPiInstallSummary(result, validation);
|
|
487
|
-
console.log(pc.cyan('\n📦 Checking Pi-managed package updates...\n'));
|
|
487
|
+
console.log(pc.cyan('\n📦 Checking Pi-managed extension package updates...\n'));
|
|
488
488
|
printPiManagedPackageUpdateResult(await updatePiManagedPackages());
|
|
489
489
|
} catch (error) {
|
|
490
490
|
console.log(pc.red('\nPi sync failed.'));
|
|
@@ -558,6 +558,8 @@ async function upgrade(target = 'all') {
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
if (normalizedTarget === 'pi') {
|
|
561
|
+
console.log(pc.cyan('\n📦 Updating Pi CLI...\n'));
|
|
562
|
+
printPiInstallResult(await updatePiCliPackage());
|
|
561
563
|
await installPiTarget({ offerOptionalFeatures: false });
|
|
562
564
|
return;
|
|
563
565
|
}
|
|
@@ -567,6 +569,8 @@ async function upgrade(target = 'all') {
|
|
|
567
569
|
return;
|
|
568
570
|
}
|
|
569
571
|
|
|
572
|
+
console.log(pc.cyan('\n📦 Updating Pi CLI...\n'));
|
|
573
|
+
printPiInstallResult(await updatePiCliPackage());
|
|
570
574
|
await installAllTargets({ offerOptionalFeatures: false });
|
|
571
575
|
console.log(pc.magenta('\n✨ Fully upgraded. Next: run `takomi` from your project.\n'));
|
|
572
576
|
}
|
|
@@ -1141,8 +1145,13 @@ program
|
|
|
1141
1145
|
.command('stats [view]')
|
|
1142
1146
|
.description('Show Takomi token, model, project, session, tool, and subagent usage stats')
|
|
1143
1147
|
.option('--json', 'Print machine-readable JSON')
|
|
1148
|
+
.option('--full', 'Print the detailed debug-style stats view')
|
|
1144
1149
|
.option('--home <path>', 'Override home directory for Pi history scanning')
|
|
1145
1150
|
.option('--cwd <path>', 'Override project directory for project-local stats')
|
|
1151
|
+
.option('--sessions-root <paths>', 'Additional session JSONL root(s), separated by ; on Windows or : on POSIX')
|
|
1152
|
+
.option('--project-root <paths>', 'Discover project-local .pi/takomi and .pi/agent/sessions roots under these path(s)')
|
|
1153
|
+
.option('--run-history <path>', 'Additional subagent run-history JSONL file')
|
|
1154
|
+
.option('--stats-config <path>', 'Local stats config JSON file (defaults to ~/.takomi/stats.local.json, then .takomi-stats.local.json)')
|
|
1146
1155
|
.option('--since <date|range>', 'Filter from YYYY-MM-DD or relative range like 7d, 4w, 3m')
|
|
1147
1156
|
.option('--limit <n>', 'Rows per section', '8')
|
|
1148
1157
|
.action((view, options) => printTakomiStats({ ...options, view, limit: Number(options.limit) || 8 }));
|