mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
feat(aiPlugin): first draft
This commit is contained in:
parent
41448e543b
commit
27171607fa
21 changed files with 4162 additions and 0 deletions
103
packages/plugin-dev/ai-productivity-prompts/README.md
Normal file
103
packages/plugin-dev/ai-productivity-prompts/README.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Procrastination Buster Plugin
|
||||
|
||||
A Super Productivity plugin that helps identify procrastination blockers and provides tailored strategies to overcome them.
|
||||
|
||||
## Features
|
||||
|
||||
- 🎯 Identify 8 different procrastination types
|
||||
- 💡 Get tailored strategies for each type
|
||||
- ⏱️ Start Pomodoro timer directly from strategies
|
||||
- ➕ Add strategies as tasks
|
||||
- 🌓 Dark mode support using CSS variables
|
||||
|
||||
## Installation
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Create plugin ZIP
|
||||
npm run package
|
||||
```
|
||||
|
||||
### Use in Super Productivity
|
||||
|
||||
1. Run `npm run build`
|
||||
2. Upload the generated `dist/plugin.zip` in Super Productivity
|
||||
3. Or copy the `dist` folder to `src/assets/procrastination-buster/`
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Shortcut**: Use keyboard shortcut for quick access
|
||||
2. **Side Panel**: Open the plugin via the side panel
|
||||
3. **Automatic**: After 15 minutes of inactivity on a task
|
||||
|
||||
## Procrastination Types
|
||||
|
||||
1. **Overwhelm** - "Too much at once"
|
||||
2. **Perfectionism** - "It's not perfect enough"
|
||||
3. **Unclear** - "I don't know what to do"
|
||||
4. **Boredom** - "It's boring"
|
||||
5. **Fear** - "I might fail"
|
||||
6. **Low Energy** - "I'm too tired"
|
||||
7. **Distraction** - "Other things are more interesting"
|
||||
8. **Resistance** - "I don't want to do this"
|
||||
|
||||
## Technology
|
||||
|
||||
- **SolidJS** for reactive UI
|
||||
- **Vite** for fast development and builds
|
||||
- **TypeScript** for type safety
|
||||
- **Super Productivity Plugin API**
|
||||
- **CSS Variables** for theme integration
|
||||
|
||||
## Development
|
||||
|
||||
The plugin consists of two parts:
|
||||
|
||||
1. **plugin.ts** - Backend logic that communicates with Super Productivity
|
||||
2. **SolidJS App** - Frontend UI in iframe
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
procrastination-buster/
|
||||
├── src/
|
||||
│ ├── plugin.ts # Plugin backend
|
||||
│ ├── App.tsx # Main component
|
||||
│ ├── types.ts # TypeScript definitions
|
||||
│ ├── BlockerSelector.tsx
|
||||
│ └── StrategyList.tsx
|
||||
├── manifest.json # Plugin metadata
|
||||
├── index.html # HTML entry
|
||||
└── vite.config.ts # Build configuration
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Add New Strategies
|
||||
|
||||
Edit `src/types.ts` and add new strategies to the appropriate types.
|
||||
|
||||
### Styling Customization
|
||||
|
||||
Edit `src/App.css` for visual adjustments. The plugin uses CSS variables for seamless theme integration:
|
||||
|
||||
- `--primary-color` - Main theme color
|
||||
- `--text-color` - Primary text
|
||||
- `--background-color` - Background
|
||||
- `--card-background` - Card backgrounds
|
||||
- `--border-radius` - Standard radius
|
||||
- And many more...
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
2659
packages/plugin-dev/ai-productivity-prompts/package-lock.json
generated
Normal file
2659
packages/plugin-dev/ai-productivity-prompts/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
28
packages/plugin-dev/ai-productivity-prompts/package.json
Normal file
28
packages/plugin-dev/ai-productivity-prompts/package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "ai-productivity-prompts-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "AI Productivity Prompts plugin for Super Productivity",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev:watch": "node scripts/watch-and-build.js",
|
||||
"build": "vite build && node scripts/inline-assets.js",
|
||||
"preview": "vite preview",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"deploy": "npm run build",
|
||||
"clean": "rm -rf dist node_modules *.zip",
|
||||
"lint": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@solidjs/router": "^0.14.10",
|
||||
"@types/node": "^22.15.33",
|
||||
"solid-js": "^1.9.7",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-solid": "^2.11.7",
|
||||
"archiver": "^7.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@super-productivity/plugin-api": "file:../../plugin-api"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
# Plugin Message Communication in Super Productivity
|
||||
|
||||
## How iframe plugins receive messages
|
||||
|
||||
### 1. Plugin registers a message handler in its iframe (index.html):
|
||||
|
||||
```javascript
|
||||
// In the plugin's index.html
|
||||
PluginAPI.onMessage(async (message) => {
|
||||
console.log('Plugin received message:', message);
|
||||
|
||||
// Handle different message types
|
||||
if (message.type === 'updateBlockedSites') {
|
||||
// Update the plugin's state
|
||||
return { success: true, sites: message.sites };
|
||||
}
|
||||
|
||||
return { error: 'Unknown message type' };
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Host app sends a message to the plugin:
|
||||
|
||||
```typescript
|
||||
// From anywhere in the Super Productivity app
|
||||
const pluginBridge = inject(PluginBridgeService);
|
||||
|
||||
const response = await pluginBridge.sendMessageToPlugin('procrastination-buster', {
|
||||
type: 'updateBlockedSites',
|
||||
sites: ['reddit.com', 'twitter.com'],
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Message flow:
|
||||
|
||||
1. `PluginBridgeService.sendMessageToPlugin()` is called
|
||||
2. It delegates to `PluginRunner.sendMessageToPlugin()`
|
||||
3. PluginRunner finds the PluginAPI instance and calls its `__sendMessage()` method
|
||||
4. For iframe plugins, this triggers a postMessage to the iframe with type `PLUGIN_MESSAGE`
|
||||
5. The iframe's message listener (set up by `onMessage`) handles the message
|
||||
6. The response is sent back via postMessage with type `PLUGIN_MESSAGE_RESPONSE`
|
||||
7. The promise resolves with the response
|
||||
|
||||
### 4. Implementation details:
|
||||
|
||||
The iframe message handling is set up in `plugin-iframe.util.ts`:
|
||||
|
||||
```javascript
|
||||
// When onMessage is called in the iframe:
|
||||
onMessage: (handler) => {
|
||||
window.__pluginMessageHandler = handler;
|
||||
window.addEventListener('message', async (event) => {
|
||||
if (event.data?.type === 'PLUGIN_MESSAGE' && window.__pluginMessageHandler) {
|
||||
try {
|
||||
const result = await window.__pluginMessageHandler(event.data.message);
|
||||
event.source?.postMessage(
|
||||
{
|
||||
type: 'PLUGIN_MESSAGE_RESPONSE',
|
||||
messageId: event.data.messageId,
|
||||
result,
|
||||
},
|
||||
'*',
|
||||
);
|
||||
} catch (error) {
|
||||
event.source?.postMessage(
|
||||
{
|
||||
type: 'PLUGIN_MESSAGE_ERROR',
|
||||
messageId: event.data.messageId,
|
||||
error: error.message,
|
||||
},
|
||||
'*',
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
However, I notice that the actual sending of `PLUGIN_MESSAGE` to the iframe is not implemented in the current code. The `__sendMessage` method on PluginAPI calls the handler directly for non-iframe plugins, but there's no code to post the message to the iframe.
|
||||
|
||||
This appears to be a missing piece in the implementation that would need to be added to complete the message communication system for iframe plugins.
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const distDir = path.join(__dirname, '../dist');
|
||||
const targetDir = path.join(
|
||||
__dirname,
|
||||
'../../../../src/assets/bundled-plugins/ai-productivity-prompts',
|
||||
);
|
||||
|
||||
// Read the HTML file
|
||||
const htmlPath = path.join(distDir, 'index.html');
|
||||
let html = fs.readFileSync(htmlPath, 'utf8');
|
||||
|
||||
// Read and inline JavaScript
|
||||
const jsPath = path.join(distDir, 'index.js');
|
||||
if (fs.existsSync(jsPath)) {
|
||||
const js = fs.readFileSync(jsPath, 'utf8');
|
||||
// Find script tag and replace with inline version, preserving type="module"
|
||||
html = html.replace(
|
||||
/<script([^>]*)src="[^"]*index\.js"[^>]*><\/script>/g,
|
||||
(match, attrs) => {
|
||||
// Check if it has type="module"
|
||||
if (attrs.includes('type="module"') || match.includes('type="module"')) {
|
||||
return `<script type="module">${js}</script>`;
|
||||
}
|
||||
return `<script>${js}</script>`;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Read and inline CSS
|
||||
const cssPath = path.join(distDir, 'index.css');
|
||||
if (fs.existsSync(cssPath)) {
|
||||
const css = fs.readFileSync(cssPath, 'utf8');
|
||||
html = html.replace(/<link[^>]*href="[^"]*index\.css"[^>]*>/g, `<style>${css}</style>`);
|
||||
}
|
||||
|
||||
// Create target directory if it doesn't exist
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
fs.mkdirSync(targetDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Write the inlined HTML to the target directory
|
||||
const targetHtmlPath = path.join(targetDir, 'index.html');
|
||||
fs.writeFileSync(targetHtmlPath, html);
|
||||
|
||||
// Copy other required files
|
||||
const filesToCopy = ['manifest.json', 'plugin.js', 'icon.svg'];
|
||||
filesToCopy.forEach((file) => {
|
||||
const srcPath = path.join(distDir, file);
|
||||
const destPath = path.join(targetDir, file);
|
||||
if (fs.existsSync(srcPath)) {
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Assets inlined and deployed successfully!');
|
||||
64
packages/plugin-dev/ai-productivity-prompts/scripts/watch-and-build.js
Executable file
64
packages/plugin-dev/ai-productivity-prompts/scripts/watch-and-build.js
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env node
|
||||
import { spawn } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.dirname(__dirname);
|
||||
|
||||
console.log('🚀 Starting development server with auto-packaging...\n');
|
||||
|
||||
// Start Vite dev server
|
||||
const viteProcess = spawn('npm', ['run', 'dev'], {
|
||||
cwd: projectRoot,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
});
|
||||
|
||||
// Watch for changes and rebuild package
|
||||
const srcPath = path.join(projectRoot, 'src');
|
||||
let buildTimeout;
|
||||
|
||||
const rebuildPackage = () => {
|
||||
if (buildTimeout) clearTimeout(buildTimeout);
|
||||
|
||||
buildTimeout = setTimeout(async () => {
|
||||
console.log('\n📦 Building plugin package...');
|
||||
|
||||
const buildProcess = spawn('npm', ['run', 'package'], {
|
||||
cwd: projectRoot,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
});
|
||||
|
||||
buildProcess.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
console.log('✅ Plugin package built successfully!\n');
|
||||
} else {
|
||||
console.error('❌ Failed to build plugin package\n');
|
||||
}
|
||||
});
|
||||
}, 1000); // Debounce for 1 second
|
||||
};
|
||||
|
||||
// Watch src directory for changes
|
||||
fs.watch(srcPath, { recursive: true }, (eventType, filename) => {
|
||||
if (filename && !filename.includes('.swp') && !filename.includes('.tmp')) {
|
||||
console.log(`📝 Change detected in ${filename}`);
|
||||
rebuildPackage();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle process termination
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n👋 Stopping development server...');
|
||||
viteProcess.kill();
|
||||
process.exit();
|
||||
});
|
||||
|
||||
viteProcess.on('close', (code) => {
|
||||
console.log(`Vite process exited with code ${code}`);
|
||||
process.exit(code);
|
||||
});
|
||||
241
packages/plugin-dev/ai-productivity-prompts/src/App.css
Normal file
241
packages/plugin-dev/ai-productivity-prompts/src/App.css
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* AI Productivity Prompts Plugin Styles
|
||||
* Simplified structure following KISS principles
|
||||
*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: transparent;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.app {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Common card styles */
|
||||
.card {
|
||||
background: var(--card-bg);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
border: 2px solid var(--extra-border-color);
|
||||
}
|
||||
|
||||
.card-clickable:hover {
|
||||
transition: transform 0.2s;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
border-color: var(--c-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Common text styles */
|
||||
.text-muted {
|
||||
color: var(--text-color-muted);
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--c-primary);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: var(--c-primary);
|
||||
}
|
||||
|
||||
.back-button {
|
||||
padding: 0.5rem 1rem;
|
||||
background: transparent;
|
||||
border: 1px solid var(--c-primary);
|
||||
color: var(--c-primary);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background: var(--c-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.intro {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.intro h2 {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Category Grid */
|
||||
.category-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.category-card h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.category-card p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Category View */
|
||||
.category-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.selected-category {
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--extra-border-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.selected-category h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Prompt List */
|
||||
.prompt-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.prompt-item {
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.prompt-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
border-color: var(--c-primary);
|
||||
}
|
||||
|
||||
.prompt-title {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Prompt View */
|
||||
.prompt-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.selected-prompt-header {
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--extra-border-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.selected-prompt-header h2 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.selected-prompt-header p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.generated-prompt {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.generated-prompt h3 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--c-primary);
|
||||
}
|
||||
|
||||
.prompt-text {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--extra-border-color);
|
||||
border-radius: 4px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
background: var(--card-bg);
|
||||
color: var(--text-color);
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.prompt-actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: var(--c-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.copy-button:disabled {
|
||||
opacity: 0.7;
|
||||
transform: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Simple page transition */
|
||||
.page-fade {
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
173
packages/plugin-dev/ai-productivity-prompts/src/App.tsx
Normal file
173
packages/plugin-dev/ai-productivity-prompts/src/App.tsx
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
import { Component, createSignal, Show, For } from 'solid-js';
|
||||
import { PROMPT_CATEGORIES, PromptCategory, renderPrompt } from './types';
|
||||
import './App.css';
|
||||
|
||||
type ViewState = 'home' | 'category' | 'prompt';
|
||||
|
||||
interface SelectedPrompt {
|
||||
category: PromptCategory;
|
||||
prompt: { title: string; template: string };
|
||||
}
|
||||
|
||||
const App: Component = () => {
|
||||
const [currentView, setCurrentView] = createSignal<ViewState>('home');
|
||||
const [selectedCategory, setSelectedCategory] = createSignal<PromptCategory | null>(
|
||||
null,
|
||||
);
|
||||
const [selectedPrompt, setSelectedPrompt] = createSignal<SelectedPrompt | null>(null);
|
||||
const [generatedPrompt, setGeneratedPrompt] = createSignal<string>('');
|
||||
|
||||
const handleSelectCategory = (category: PromptCategory) => {
|
||||
setSelectedCategory(category);
|
||||
setCurrentView('category');
|
||||
};
|
||||
|
||||
const handleSelectPrompt = async (prompt: { title: string; template: string }) => {
|
||||
const category = selectedCategory();
|
||||
if (!category) return;
|
||||
|
||||
// Get current tasks from Super Productivity
|
||||
const pluginAPI = (window as any).PluginAPI;
|
||||
let tasksMd = '';
|
||||
|
||||
if (pluginAPI) {
|
||||
try {
|
||||
// Try to get current tasks as markdown
|
||||
const tasks = await pluginAPI.getCurrentTasks?.();
|
||||
if (tasks && tasks.length > 0) {
|
||||
tasksMd = tasks.map((task: any) => `- [ ] ${task.title}`).join('\n');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Could not fetch tasks:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const rendered = renderPrompt(prompt.template, tasksMd);
|
||||
setGeneratedPrompt(rendered);
|
||||
setSelectedPrompt({ category, prompt });
|
||||
setCurrentView('prompt');
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
if (currentView() === 'prompt') {
|
||||
setCurrentView('category');
|
||||
setSelectedPrompt(null);
|
||||
setGeneratedPrompt('');
|
||||
} else if (currentView() === 'category') {
|
||||
setCurrentView('home');
|
||||
setSelectedCategory(null);
|
||||
}
|
||||
};
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(generatedPrompt());
|
||||
// Show a brief success message
|
||||
const button = document.querySelector('.copy-button') as HTMLButtonElement;
|
||||
if (button) {
|
||||
const originalText = button.textContent;
|
||||
button.textContent = 'Copied!';
|
||||
button.disabled = true;
|
||||
setTimeout(() => {
|
||||
button.textContent = originalText;
|
||||
button.disabled = false;
|
||||
}, 1500);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to copy:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="app">
|
||||
<Show when={currentView() !== 'home'}>
|
||||
<header class="header page-fade">
|
||||
<button
|
||||
class="back-button"
|
||||
onClick={handleBack}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
</header>
|
||||
</Show>
|
||||
|
||||
<main class="main">
|
||||
{/* Home View */}
|
||||
<Show when={currentView() === 'home'}>
|
||||
<div class="intro page-fade">
|
||||
<h2>AI Productivity Prompts</h2>
|
||||
<p class="text-muted">Choose what you need help with:</p>
|
||||
</div>
|
||||
|
||||
<div class="category-grid page-fade">
|
||||
<For each={PROMPT_CATEGORIES}>
|
||||
{(category) => (
|
||||
<button
|
||||
class="category-card card card-clickable"
|
||||
onClick={() => handleSelectCategory(category)}
|
||||
>
|
||||
<h3 class="text-primary">{category.title}</h3>
|
||||
<p class="text-muted">{category.prompts.length} prompts</p>
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
{/* Category View */}
|
||||
<Show when={currentView() === 'category' && selectedCategory()}>
|
||||
<div class="category-container page-fade">
|
||||
<div class="selected-category">
|
||||
<h2 class="text-primary">{selectedCategory()!.title}</h2>
|
||||
</div>
|
||||
|
||||
<h3>Available Prompts:</h3>
|
||||
|
||||
<div class="prompt-list">
|
||||
<For each={selectedCategory()!.prompts}>
|
||||
{(prompt) => (
|
||||
<button
|
||||
class="prompt-item card card-clickable"
|
||||
onClick={() => handleSelectPrompt(prompt)}
|
||||
>
|
||||
<h4 class="prompt-title">{prompt.title}</h4>
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
{/* Prompt View */}
|
||||
<Show when={currentView() === 'prompt' && selectedPrompt()}>
|
||||
<div class="prompt-container page-fade">
|
||||
<div class="selected-prompt-header">
|
||||
<h2 class="text-primary">{selectedPrompt()!.prompt.title}</h2>
|
||||
<p class="text-muted">From: {selectedPrompt()!.category.title}</p>
|
||||
</div>
|
||||
|
||||
<div class="generated-prompt card">
|
||||
<h3>Generated Prompt:</h3>
|
||||
<textarea
|
||||
class="prompt-text"
|
||||
value={generatedPrompt()}
|
||||
readonly
|
||||
rows="15"
|
||||
/>
|
||||
<div class="prompt-actions">
|
||||
<button
|
||||
class="copy-button"
|
||||
onClick={copyToClipboard}
|
||||
>
|
||||
📋 Copy to clipboard
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
import { Component } from 'solid-js';
|
||||
import './App.css';
|
||||
|
||||
interface ProcrastinationInfoProps {
|
||||
onBackToWork: () => void;
|
||||
}
|
||||
|
||||
export const ProcrastinationInfo: Component<ProcrastinationInfoProps> = (props) => {
|
||||
return (
|
||||
<div class="page-fade info-content">
|
||||
<div class="intro">
|
||||
<h2>Understanding Procrastination</h2>
|
||||
<p>
|
||||
<strong>
|
||||
Procrastination is an emotion regulation problem, not a time management
|
||||
problem.
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h3>The Procrastination Cycle</h3>
|
||||
<p>
|
||||
When we face tasks that trigger uncomfortable emotions, we enter a feedback
|
||||
loop:
|
||||
</p>
|
||||
<div class="procrastination-graph">
|
||||
<div class="graph-item">Fear of failure</div>
|
||||
<div class="sync-icon">→</div>
|
||||
<div class="graph-item">Avoid the task</div>
|
||||
<div class="sync-icon">→</div>
|
||||
<div class="graph-item">Temporary relief</div>
|
||||
<div class="sync-icon">→</div>
|
||||
<div class="graph-item">Increased anxiety</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Breaking the Cycle</h3>
|
||||
<p>
|
||||
The key is to approach procrastination with curiosity and compassion, not
|
||||
judgment. Ask yourself:
|
||||
</p>
|
||||
<ul>
|
||||
<li>What emotions come up when I think about this task?</li>
|
||||
<li>What specific aspect feels most challenging?</li>
|
||||
<li>What am I afraid might happen if I start?</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Practical Strategies</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Start small:</strong> What's the tiniest first step you could take?
|
||||
</li>
|
||||
<li>
|
||||
<strong>Time-box:</strong> Work for just 10-25 minutes, then take a break
|
||||
</li>
|
||||
<li>
|
||||
<strong>Reframe:</strong> Focus on progress over perfection
|
||||
</li>
|
||||
<li>
|
||||
<strong>Self-compassion:</strong> Speak to yourself as you would to a good
|
||||
friend
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Common Triggers</h3>
|
||||
<p>
|
||||
Procrastination is often triggered by perfectionism, fear of failure, feeling
|
||||
overwhelmed, unclear expectations, or finding the task boring. Identifying your
|
||||
specific trigger is the first step to moving forward.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button
|
||||
class="primary-button"
|
||||
onClick={props.onBackToWork}
|
||||
>
|
||||
Back to work!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||
<g transform="translate(50,50)">
|
||||
<!-- Full size star shape -->
|
||||
<path d="M 0,-45 L 11.25,-11.25 L 45,-13.5 L 15.75,6.75 L 22.5,40.5 L 0,13.5 L -22.5,40.5 L -15.75,6.75 L -45,-13.5 L -11.25,-11.25 Z" fill="currentColor" stroke="currentColor" stroke-width="2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 371 B |
18
packages/plugin-dev/ai-productivity-prompts/src/index.html
Normal file
18
packages/plugin-dev/ai-productivity-prompts/src/index.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
<title>Procrastination Buster</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script
|
||||
type="module"
|
||||
src="./index.tsx"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
17
packages/plugin-dev/ai-productivity-prompts/src/index.tsx
Normal file
17
packages/plugin-dev/ai-productivity-prompts/src/index.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* @refresh reload */
|
||||
import { render } from 'solid-js/web';
|
||||
import App from './App';
|
||||
|
||||
const root = document.getElementById('root');
|
||||
|
||||
function waitForPluginAPI() {
|
||||
if (typeof (window as any).PluginAPI !== 'undefined') {
|
||||
if (root) {
|
||||
render(() => <App />, root);
|
||||
}
|
||||
} else {
|
||||
setTimeout(waitForPluginAPI, 100);
|
||||
}
|
||||
}
|
||||
|
||||
waitForPluginAPI();
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "AI Productivity Prompts",
|
||||
"id": "ai-productivity-prompts",
|
||||
"manifestVersion": 1,
|
||||
"version": "1.0.0",
|
||||
"minSupVersion": "13.0.0",
|
||||
"description": "AI-powered productivity prompts to help you plan your day, week, and overcome challenges",
|
||||
"author": "Super Productivity Community",
|
||||
"homepage": "https://github.com/johannesjo/super-productivity",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/johannesjo/super-productivity.git"
|
||||
},
|
||||
"hooks": ["currentTaskChange"],
|
||||
"permissions": ["showSnack", "openDialog", "addTask", "showIndexHtmlAsView"],
|
||||
"iFrame": true,
|
||||
"sidePanel": true,
|
||||
"isSkipMenuEntry": false,
|
||||
"icon": "icon.svg"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// Procrastination Buster Plugin for Super Productivity
|
||||
// import { PluginInterface } from '@super-productivity/plugin-api';
|
||||
// declare const plugin: PluginInterface;
|
||||
47
packages/plugin-dev/ai-productivity-prompts/src/types.d.ts
vendored
Normal file
47
packages/plugin-dev/ai-productivity-prompts/src/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { SnackType, PluginMessageType } from './types';
|
||||
|
||||
// Plugin message interfaces
|
||||
interface PluginMessage {
|
||||
type: PluginMessageType;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface AddStrategyTaskMessage extends PluginMessage {
|
||||
type: PluginMessageType.ADD_STRATEGY_TASK;
|
||||
strategy: string;
|
||||
blockerType: string;
|
||||
}
|
||||
|
||||
interface StartPomodoroMessage extends PluginMessage {
|
||||
type: PluginMessageType.START_POMODORO;
|
||||
}
|
||||
|
||||
interface StartFocusModeMessage extends PluginMessage {
|
||||
type: PluginMessageType.START_FOCUS_MODE;
|
||||
}
|
||||
|
||||
interface QuickAddTaskMessage extends PluginMessage {
|
||||
type: PluginMessageType.QUICK_ADD_TASK;
|
||||
}
|
||||
|
||||
type AllPluginMessages =
|
||||
| AddStrategyTaskMessage
|
||||
| StartPomodoroMessage
|
||||
| StartFocusModeMessage
|
||||
| QuickAddTaskMessage;
|
||||
|
||||
// Window interface augmentation
|
||||
declare global {
|
||||
interface Window {
|
||||
PluginAPI?: {
|
||||
showSnack: (config: { msg: string; type?: SnackType }) => void;
|
||||
openDialog: (config: any) => Promise<void>;
|
||||
onMessage: (handler: (message: AllPluginMessages) => Promise<any>) => void;
|
||||
addTask: (task: { title: string; notes?: string }) => Promise<string>;
|
||||
dispatchAction: (action: { type: string; [key: string]: any }) => void;
|
||||
};
|
||||
__pluginMessageHandler?: (message: AllPluginMessages) => Promise<any>;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
405
packages/plugin-dev/ai-productivity-prompts/src/types.ts
Normal file
405
packages/plugin-dev/ai-productivity-prompts/src/types.ts
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
// ============================================================================
|
||||
// Interfaces
|
||||
// ============================================================================
|
||||
|
||||
export interface PromptCategory {
|
||||
title: string;
|
||||
prompts: {
|
||||
title: string;
|
||||
template: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Renders a prompt template with optional tasks markdown
|
||||
*/
|
||||
export function renderPrompt(template: string, tasksMd?: string): string {
|
||||
return template.replace(/{{#if tasks_md}}([\s\S]*?){{\/if}}/g, (match, content) => {
|
||||
if (tasksMd) {
|
||||
return content.replace(/{{tasks_md}}/g, tasksMd);
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Data
|
||||
// ============================================================================
|
||||
|
||||
export const PROMPT_CATEGORIES: PromptCategory[] = [
|
||||
{
|
||||
title: 'What should I do today?',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Pick my Top 3 for today',
|
||||
template: `You are an executive function coach. Given my tasks, help me pick a realistic Top 3 for today. Consider:
|
||||
|
||||
- What has the highest impact?
|
||||
- What's time-sensitive or has dependencies?
|
||||
- What can I realistically complete given my energy and schedule?
|
||||
- Balance between urgent and important tasks
|
||||
|
||||
Provide specific reasoning for each choice and suggest a rough time estimate.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Here are my tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: '90-Minute Sprint',
|
||||
template: `Create a single 90-minute sprint plan from these tasks. Include:
|
||||
|
||||
- **One primary objective** (what success looks like)
|
||||
- **3–5 atomic steps** (specific, actionable items)
|
||||
- **Definition of done** (how you'll know it's complete)
|
||||
- **5-minute warm-up ritual** (to get into flow)
|
||||
- **5-minute cooldown + log** (to capture what you learned)
|
||||
|
||||
Focus on deep work that moves the needle forward.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Energy-Based Schedule',
|
||||
template: `Help me schedule my day based on my energy patterns and task requirements. Suggest:
|
||||
|
||||
- **High-energy tasks** for when I'm sharpest (usually morning)
|
||||
- **Medium-energy tasks** for mid-day
|
||||
- **Low-energy tasks** for when I'm tired
|
||||
- **Buffer time** between demanding tasks
|
||||
- **Recovery breaks** to maintain productivity
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks to schedule:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Plan my week',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Weekly Game Plan',
|
||||
template: `Plan my week with a strategic approach:
|
||||
|
||||
1. **1–3 weekly outcomes** (what must be accomplished this week)
|
||||
2. **Required tasks** for each outcome
|
||||
3. **Draft schedule** by weekday (considering energy and commitments)
|
||||
4. **Risks and buffers** (what could go wrong, how to prepare)
|
||||
5. **'One thing' fallback** (if everything goes sideways, what's the minimum viable success?)
|
||||
|
||||
Focus on outcomes over activities.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Candidate tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Theme Days',
|
||||
template: `Organize my week using theme days to batch similar work and reduce context switching:
|
||||
|
||||
- **Monday**: Planning & Strategy
|
||||
- **Tuesday**: Deep Work & Creation
|
||||
- **Wednesday**: Communication & Meetings
|
||||
- **Thursday**: Implementation & Building
|
||||
- **Friday**: Review & Administrative Tasks
|
||||
|
||||
Assign my tasks to appropriate theme days and suggest how to batch related work.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks to organize:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "I'm procrastinating",
|
||||
prompts: [
|
||||
{
|
||||
title: 'Anti-Procrastination Coach',
|
||||
template: `I'm procrastinating. Help me identify the likely blockers and provide specific solutions:
|
||||
|
||||
**Common blockers to check:**
|
||||
- **Fear** (of failure, judgment, or success)
|
||||
- **Ambiguity** (unclear next steps)
|
||||
- **Overwhelm** (task feels too big)
|
||||
- **Boredom** (task feels tedious)
|
||||
- **Perfectionism** (standards too high)
|
||||
|
||||
For each relevant blocker, give me:
|
||||
1. A **tiny next action** (<10 minutes)
|
||||
2. A **'first ugly draft' approach**
|
||||
3. A specific **reframing** technique
|
||||
|
||||
{{#if tasks_md}}
|
||||
Context:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: '2-Minute Rule',
|
||||
template: `Apply the 2-minute rule to break through procrastination:
|
||||
|
||||
1. **Identify the absolute smallest step** I can take (under 2 minutes)
|
||||
2. **Remove all barriers** to starting that step
|
||||
3. **Set up the environment** for success
|
||||
4. **Create momentum** with a micro-commitment
|
||||
|
||||
Remember: You're not committing to finish, just to start. Starting is often the hardest part.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks I'm avoiding:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'I feel overwhelmed',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Triage & Tame',
|
||||
template: `Help me triage these tasks and create a 2-hour rescue plan:
|
||||
|
||||
**Step 1: Triage into three buckets:**
|
||||
- **Now** (must be done today, high impact)
|
||||
- **Next** (important but can wait 24-48 hours)
|
||||
- **Not Now** (low priority or can be delayed/delegated)
|
||||
|
||||
**Step 2: Create a 2-hour rescue plan:**
|
||||
- Pick ONE task from "Now" bucket
|
||||
- Break it into 20-minute chunks
|
||||
- Include 10-minute breaks between chunks
|
||||
- End with a 15-minute planning session for tomorrow
|
||||
|
||||
Focus on progress over perfection.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Stress Audit',
|
||||
template: `Let's do a quick stress audit to identify what's really driving the overwhelm:
|
||||
|
||||
1. **Task overload** - Too many things on my plate?
|
||||
2. **Time pressure** - Unrealistic deadlines?
|
||||
3. **Skill gaps** - Missing knowledge or tools?
|
||||
4. **Decision fatigue** - Too many choices to make?
|
||||
5. **External pressure** - Others' expectations?
|
||||
|
||||
For each factor present, suggest one specific action to reduce its impact this week.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Current tasks and commitments:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'I am not motivated',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Make It Attractive',
|
||||
template: `Rewrite my tasks to be more motivating and engaging:
|
||||
|
||||
For each task, help me:
|
||||
1. **Add a why-statement** (connect to bigger purpose)
|
||||
2. **Reframe the outcome** (focus on benefits, not effort)
|
||||
3. **Suggest a reward** (something I'll enjoy after completion)
|
||||
4. **Create a 5-minute starter ritual** (make beginning easier)
|
||||
5. **Find the learning opportunity** (what skill will I develop?)
|
||||
|
||||
Transform tasks from chores into opportunities.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks to make attractive:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Motivation Reset',
|
||||
template: `Help me reset my motivation by reconnecting with my deeper drivers:
|
||||
|
||||
1. **Values alignment** - How do these tasks connect to what I care about?
|
||||
2. **Progress visualization** - What will completing this enable?
|
||||
3. **Identity reinforcement** - What kind of person does this work?
|
||||
4. **Energy audit** - When am I most naturally motivated?
|
||||
5. **Environmental design** - How can I set up my space for success?
|
||||
|
||||
Create a personalized motivation plan based on my specific situation.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Current tasks and goals:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "I can't focus",
|
||||
prompts: [
|
||||
{
|
||||
title: 'Focus Troubleshoot',
|
||||
template: `Let's diagnose and fix focus issues systematically:
|
||||
|
||||
**Common focus killers:**
|
||||
- **Digital distractions** (notifications, social media)
|
||||
- **Mental clutter** (unfinished tasks, decisions)
|
||||
- **Physical environment** (noise, clutter, comfort)
|
||||
- **Energy state** (hunger, fatigue, stress)
|
||||
- **Task design** (too vague, too big, too boring)
|
||||
|
||||
For each relevant issue, I'll provide:
|
||||
1. A **quick fix** for right now
|
||||
2. A **system** to prevent it recurring
|
||||
3. A **focus ritual** to get back on track
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks requiring focus:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Deep Work Block',
|
||||
template: `Design a deep work block for maximum focus and productivity:
|
||||
|
||||
**Pre-work setup (5 minutes):**
|
||||
- Clear physical and digital space
|
||||
- Set specific intention and outcome
|
||||
- Eliminate distractions and notifications
|
||||
|
||||
**Work block structure:**
|
||||
- 25-45 minute focused sprint
|
||||
- Clear start and stop signals
|
||||
- Single task focus (no multitasking)
|
||||
|
||||
**Recovery (10 minutes):**
|
||||
- Note progress and insights
|
||||
- Physical movement or fresh air
|
||||
- Prepare for next session
|
||||
|
||||
Customize this framework for your specific needs and tasks.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Tasks for deep work:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Review and reflect',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Daily Review',
|
||||
template: `Guide me through a productive daily review:
|
||||
|
||||
**What happened today:**
|
||||
1. What did I complete? (celebrate wins, even small ones)
|
||||
2. What didn't get done? (without judgment, just facts)
|
||||
3. What surprised me? (unexpected challenges or insights)
|
||||
|
||||
**Learning and adjustment:**
|
||||
4. What worked well? (systems, approaches, decisions to repeat)
|
||||
5. What would I do differently? (specific adjustments for tomorrow)
|
||||
6. What patterns do I notice? (energy, focus, productivity trends)
|
||||
|
||||
**Tomorrow's setup:**
|
||||
7. What are my top 3 priorities?
|
||||
8. What potential obstacles should I prepare for?
|
||||
|
||||
{{#if tasks_md}}
|
||||
Today's tasks and activities:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Weekly Retrospective',
|
||||
template: `Conduct a comprehensive weekly retrospective:
|
||||
|
||||
**Week in review:**
|
||||
1. **Wins and accomplishments** (what am I proud of?)
|
||||
2. **Challenges and obstacles** (what was harder than expected?)
|
||||
3. **Progress toward goals** (am I on track with bigger objectives?)
|
||||
|
||||
**Systems and processes:**
|
||||
4. **What's working well?** (tools, habits, routines to keep)
|
||||
5. **What needs adjustment?** (pain points to address next week)
|
||||
6. **What experiments should I try?** (one small thing to test)
|
||||
|
||||
**Next week preparation:**
|
||||
7. **Key outcomes** (what success looks like)
|
||||
8. **Potential risks** (what could derail progress)
|
||||
9. **Energy management** (how to maintain sustainable productivity)
|
||||
|
||||
{{#if tasks_md}}
|
||||
This week's tasks and outcomes:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Prepare for meetings',
|
||||
prompts: [
|
||||
{
|
||||
title: 'Meeting Prep Assistant',
|
||||
template: `Help me prepare for productive meetings:
|
||||
|
||||
**Before the meeting:**
|
||||
1. **Clear objective** - What specific outcome do we need?
|
||||
2. **My role** - How can I contribute most effectively?
|
||||
3. **Key questions** - What do I need to ask or clarify?
|
||||
4. **Preparation needed** - What should I review or bring?
|
||||
|
||||
**During the meeting:**
|
||||
5. **Focus points** - What are the most important items?
|
||||
6. **Decision needs** - What requires resolution today?
|
||||
7. **Action items** - Who does what by when?
|
||||
|
||||
**After the meeting:**
|
||||
8. **Follow-up actions** - What are my next steps?
|
||||
9. **Communication** - Who needs to be updated?
|
||||
|
||||
{{#if tasks_md}}
|
||||
Meeting context and related tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
{
|
||||
title: 'Difficult Conversation Prep',
|
||||
template: `Prepare for a challenging conversation with confidence and clarity:
|
||||
|
||||
**Preparation framework:**
|
||||
1. **Objective** - What outcome do I want? (be specific and realistic)
|
||||
2. **Their perspective** - What might they be thinking/feeling?
|
||||
3. **Common ground** - Where do our interests align?
|
||||
4. **Key points** - What are my 2-3 most important messages?
|
||||
5. **Evidence** - What facts support my position?
|
||||
6. **Compromise options** - Where can I be flexible?
|
||||
7. **Worst case plan** - How will I handle pushback or conflict?
|
||||
|
||||
Focus on mutual problem-solving rather than winning.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Context and background:
|
||||
{{tasks_md}}
|
||||
{{/if}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Simple test for the renderPrompt function - FIXED VERSION
|
||||
|
||||
function renderPrompt(template, tasksMd) {
|
||||
return template.replace(/{{#if tasks_md}}([\s\S]*?){{\/if}}/g, (match, content) => {
|
||||
if (tasksMd) {
|
||||
return content.replace(/{{tasks_md}}/g, tasksMd);
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
// Test cases
|
||||
console.log('Test 1 - Without tasks:');
|
||||
const template1 = 'Hello {{#if tasks_md}}here are tasks: {{tasks_md}}{{/if}} end.';
|
||||
console.log(renderPrompt(template1));
|
||||
|
||||
console.log('\nTest 2 - With tasks:');
|
||||
console.log(renderPrompt(template1, '- Task 1\n- Task 2'));
|
||||
|
||||
console.log('\nTest 3 - Real prompt template:');
|
||||
const realTemplate = `You are an executive function coach. Given my tasks, help me pick a realistic Top 3 for today.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Here are my tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`;
|
||||
|
||||
console.log('Without tasks:');
|
||||
console.log(renderPrompt(realTemplate));
|
||||
|
||||
console.log('\nWith tasks:');
|
||||
console.log(
|
||||
renderPrompt(
|
||||
realTemplate,
|
||||
'- [ ] Complete project report\n- [ ] Review PR #123\n- [ ] Meeting with team',
|
||||
),
|
||||
);
|
||||
35
packages/plugin-dev/ai-productivity-prompts/test-template.js
Normal file
35
packages/plugin-dev/ai-productivity-prompts/test-template.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Simple test for the renderPrompt function
|
||||
|
||||
function renderPrompt(template, tasksMd) {
|
||||
return template.replace(
|
||||
/{{#if tasks_md}}([\s\S]*?){{\/if}}/g,
|
||||
tasksMd ? `$1`.replace(/{{tasks_md}}/g, tasksMd) : '',
|
||||
);
|
||||
}
|
||||
|
||||
// Test cases
|
||||
console.log('Test 1 - Without tasks:');
|
||||
const template1 = 'Hello {{#if tasks_md}}here are tasks: {{tasks_md}}{{/if}} end.';
|
||||
console.log(renderPrompt(template1));
|
||||
|
||||
console.log('\nTest 2 - With tasks:');
|
||||
console.log(renderPrompt(template1, '- Task 1\n- Task 2'));
|
||||
|
||||
console.log('\nTest 3 - Real prompt template:');
|
||||
const realTemplate = `You are an executive function coach. Given my tasks, help me pick a realistic Top 3 for today.
|
||||
|
||||
{{#if tasks_md}}
|
||||
Here are my tasks:
|
||||
{{tasks_md}}
|
||||
{{/if}}`;
|
||||
|
||||
console.log('Without tasks:');
|
||||
console.log(renderPrompt(realTemplate));
|
||||
|
||||
console.log('\nWith tasks:');
|
||||
console.log(
|
||||
renderPrompt(
|
||||
realTemplate,
|
||||
'- [ ] Complete project report\n- [ ] Review PR #123\n- [ ] Meeting with team',
|
||||
),
|
||||
);
|
||||
19
packages/plugin-dev/ai-productivity-prompts/tsconfig.json
Normal file
19
packages/plugin-dev/ai-productivity-prompts/tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"noEmit": true,
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
55
packages/plugin-dev/ai-productivity-prompts/vite.config.ts
Normal file
55
packages/plugin-dev/ai-productivity-prompts/vite.config.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import solidPlugin from 'vite-plugin-solid';
|
||||
import { resolve } from 'path';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
plugins: [
|
||||
solidPlugin(),
|
||||
{
|
||||
name: 'copy-files',
|
||||
closeBundle() {
|
||||
// Copy manifest.json to dist
|
||||
const manifestSrc = path.resolve(__dirname, 'src/manifest.json');
|
||||
const manifestDest = path.resolve(__dirname, 'dist/manifest.json');
|
||||
fs.copyFileSync(manifestSrc, manifestDest);
|
||||
|
||||
// Copy icon.svg to dist root
|
||||
const iconSrc = path.resolve(__dirname, 'src/assets/icon.svg');
|
||||
const iconDest = path.resolve(__dirname, 'dist/icon.svg');
|
||||
fs.copyFileSync(iconSrc, iconDest);
|
||||
|
||||
// Move index.html from src subdirectory to root
|
||||
const htmlSrc = path.resolve(__dirname, 'dist/src/index.html');
|
||||
const htmlDest = path.resolve(__dirname, 'dist/index.html');
|
||||
if (fs.existsSync(htmlSrc)) {
|
||||
fs.renameSync(htmlSrc, htmlDest);
|
||||
// Remove the src directory
|
||||
fs.rmSync(path.resolve(__dirname, 'dist/src'), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, 'src/index.html'),
|
||||
plugin: resolve(__dirname, 'src/plugin.ts'),
|
||||
},
|
||||
output: {
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name]-[hash].js',
|
||||
assetFileNames: '[name].[ext]',
|
||||
},
|
||||
},
|
||||
copyPublicDir: false,
|
||||
},
|
||||
publicDir: 'src/assets',
|
||||
});
|
||||
|
|
@ -94,6 +94,7 @@ export class PluginService implements OnDestroy {
|
|||
'assets/bundled-plugins/sync-md',
|
||||
'assets/bundled-plugins/api-test-plugin',
|
||||
'assets/bundled-plugins/procrastination-buster',
|
||||
'assets/bundled-plugins/ai-productivity-prompts',
|
||||
];
|
||||
|
||||
// Only load manifests for discovery
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue