vibepulse 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/bin/vibepulse.js +56 -0
- package/dist/index.d.mts +137 -0
- package/dist/index.d.ts +137 -0
- package/dist/index.js +74 -0
- package/dist/index.mjs +43 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# VibePulse
|
|
2
|
+
|
|
3
|
+
Real-time dashboard for monitoring and managing OpenCode sessions.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
### Session Management
|
|
10
|
+
- **Real-time sync** — Automatically syncs OpenCode sessions via SSE + polling
|
|
11
|
+
- **4-column board** — Idle, Busy, Review, Done
|
|
12
|
+
- **Drag & drop** — Reorder cards within columns
|
|
13
|
+
- **IDE integration** — Click to open workspace in VSCode / Antigravity
|
|
14
|
+
- **Audio notifications** — Sound alerts when sessions complete or need attention
|
|
15
|
+
- **Process hints** — Detects OpenCode processes without exposed API ports
|
|
16
|
+
- **Offline snapshot** — Displays last known state when OpenCode is unreachable
|
|
17
|
+
- **Auto-generated cards** — No manual card creation needed
|
|
18
|
+
|
|
19
|
+
### Configuration Management (New)
|
|
20
|
+
- **Profile System** — Create and manage multiple configuration profiles for different workflows
|
|
21
|
+
- Built-in profiles (e.g., "Balanced") with optimized agent/category configurations
|
|
22
|
+
- Custom profiles with user-defined settings
|
|
23
|
+
- One-click profile switching
|
|
24
|
+
- **Reset to Profile** — After applying a profile, if you modify configs elsewhere, click "Reset" to restore the profile's original values (with confirmation dialog)
|
|
25
|
+
- **Agent Configuration** — Configure models, temperature, and other parameters for each agent (sisyphus, oracle, librarian, etc.)
|
|
26
|
+
- **Category Configuration** — Set up model preferences for different task categories (visual-engineering, ultrabrain, deep, quick, etc.)
|
|
27
|
+
- **Model Selector** — Smart model selection with grouped providers and search; shows error state with retry button if model fetch fails
|
|
28
|
+
|
|
29
|
+
## Tech Stack
|
|
30
|
+
|
|
31
|
+
- Next.js (App Router)
|
|
32
|
+
- TypeScript
|
|
33
|
+
- Tailwind CSS
|
|
34
|
+
- @dnd-kit (drag and drop)
|
|
35
|
+
- TanStack Query (state management)
|
|
36
|
+
- @opencode-ai/sdk
|
|
37
|
+
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
### Quick Start (npx)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Run directly without installing
|
|
44
|
+
npx vibepulse
|
|
45
|
+
|
|
46
|
+
# Or specify a custom port
|
|
47
|
+
PORT=8080 npx vibepulse
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Open [http://localhost:3456](http://localhost:3456)
|
|
51
|
+
|
|
52
|
+
### Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Install dependencies
|
|
56
|
+
npm install
|
|
57
|
+
|
|
58
|
+
# Make sure OpenCode is running locally, then:
|
|
59
|
+
npm run dev
|
|
60
|
+
|
|
61
|
+
# Or specify a custom port
|
|
62
|
+
PORT=8080 npm run dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Open [http://localhost:3456](http://localhost:3456) (default port: 3456)
|
|
66
|
+
|
|
67
|
+
## Architecture
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
71
|
+
│ Browser │────▶│ Next.js │────▶│ OpenCode │
|
|
72
|
+
│ │◀────│ API │◀────│ SDK │
|
|
73
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
74
|
+
│ │
|
|
75
|
+
└───────────────────┘
|
|
76
|
+
SSE Events (real-time)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
📖 **Session Status Detection**: See [docs/session-status-detection.md](./docs/session-status-detection.md) for detailed explanation of how session statuses are detected, including the sticky state mechanism and detection limitations.
|
|
80
|
+
|
|
81
|
+
## How It Works
|
|
82
|
+
|
|
83
|
+
### Session Management
|
|
84
|
+
1. Discovers OpenCode instances via port scanning and process detection
|
|
85
|
+
2. Fetches sessions from OpenCode SDK with 5-second polling
|
|
86
|
+
3. SSE connection provides real-time updates for immediate feedback
|
|
87
|
+
4. Multi-layer status detection (see [docs/session-status-detection.md](./docs/session-status-detection.md)):
|
|
88
|
+
- Analyzes message part states (running/completed/waiting)
|
|
89
|
+
- Applies sticky state buffering to prevent flickering
|
|
90
|
+
- Cascades child session status to parent sessions
|
|
91
|
+
5. Cards are auto-generated and organized into kanban columns
|
|
92
|
+
|
|
93
|
+
### Configuration Management
|
|
94
|
+
1. **Profiles** are stored in `~/.config/opencode/profiles/`
|
|
95
|
+
2. **Applying a Profile** overwrites your current agent and category configurations
|
|
96
|
+
3. **Reset Functionality** — When a profile shows "Reset" button:
|
|
97
|
+
- The profile was previously applied but configs have been modified
|
|
98
|
+
- Click "Reset" and confirm to restore the profile's original values
|
|
99
|
+
4. **Model Fetching** — Models are fetched from `opencode models` CLI command; if it fails, an error state is shown with a retry button (no fallback models)
|
|
100
|
+
|
|
101
|
+
## Troubleshooting
|
|
102
|
+
|
|
103
|
+
### Configuration Management
|
|
104
|
+
|
|
105
|
+
#### Models not loading / "Failed to fetch models" error
|
|
106
|
+
- Ensure `opencode` CLI is installed and available in your PATH
|
|
107
|
+
- Check that `~/.opencode/bin` is in your PATH
|
|
108
|
+
- Click the **Retry** button in the model selector to attempt fetching again
|
|
109
|
+
- Run `opencode models` in your terminal to verify CLI is working
|
|
110
|
+
|
|
111
|
+
#### Profile Reset not working
|
|
112
|
+
- Make sure the profile was previously applied (shows "Reset" button instead of "Apply")
|
|
113
|
+
- The reset requires confirmation — check that you clicked "Reset" in the confirmation dialog
|
|
114
|
+
- If configs still don't reset, try re-applying the profile from the profile list
|
|
115
|
+
|
|
116
|
+
#### Board shows "No sessions found"
|
|
117
|
+
- Ensure OpenCode is running locally
|
|
118
|
+
- Check that the SDK can connect (port conflicts)
|
|
119
|
+
- Look for the ℹ️ icon in the header for process hints
|
|
120
|
+
|
|
121
|
+
### Session status flickers or seems inaccurate
|
|
122
|
+
- This is a known limitation due to sparse OpenCode status signals
|
|
123
|
+
- See [docs/session-status-detection.md](./docs/session-status-detection.md) for detailed explanation
|
|
124
|
+
- The board uses 25-second sticky buffering to reduce flickering
|
|
125
|
+
|
|
126
|
+
### IDE doesn't open
|
|
127
|
+
- Make sure VSCode / Antigravity is installed
|
|
128
|
+
- Check that the corresponding protocol handler is registered (e.g. `vscode://`)
|
|
129
|
+
|
|
130
|
+
### Prevent VSCode from replacing an existing window
|
|
131
|
+
|
|
132
|
+
Open VSCode Settings (JSON) and add:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
"window.openFoldersInNewWindow": "on"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Known Limitations
|
|
139
|
+
|
|
140
|
+
- Single user only (no collaboration)
|
|
141
|
+
- Card positions stored in LocalStorage only
|
|
142
|
+
- Cannot focus specific IDE window (opens workspace)
|
|
143
|
+
- No manual card creation/editing
|
|
144
|
+
- Session status detection has inherent limitations (see [docs/session-status-detection.md](./docs/session-status-detection.md))
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
package/bin/vibepulse.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
const port = process.env.PORT || '3456';
|
|
8
|
+
|
|
9
|
+
console.log(`🚀 Starting VibePulse on port ${port}...`);
|
|
10
|
+
console.log(`📊 Open http://localhost:${port} to view the dashboard`);
|
|
11
|
+
console.log('');
|
|
12
|
+
|
|
13
|
+
// Try to find next binary
|
|
14
|
+
let nextBin;
|
|
15
|
+
const possiblePaths = [
|
|
16
|
+
// Local development
|
|
17
|
+
path.join(__dirname, '..', 'node_modules', '.bin', 'next'),
|
|
18
|
+
// Global install
|
|
19
|
+
path.join(__dirname, '..', '..', '.bin', 'next'),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
for (const p of possiblePaths) {
|
|
23
|
+
if (fs.existsSync(p)) {
|
|
24
|
+
nextBin = p;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!nextBin) {
|
|
30
|
+
// Try using npx
|
|
31
|
+
nextBin = 'npx';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const args = nextBin === 'npx'
|
|
35
|
+
? ['next', 'dev', '-p', port]
|
|
36
|
+
: ['dev', '-p', port];
|
|
37
|
+
|
|
38
|
+
const proc = spawn(nextBin, args, {
|
|
39
|
+
cwd: path.join(__dirname, '..'),
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
env: {
|
|
42
|
+
...process.env,
|
|
43
|
+
PORT: port
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
proc.on('error', (err) => {
|
|
48
|
+
console.error('Failed to start VibePulse:', err.message);
|
|
49
|
+
console.error('\nMake sure you have Next.js installed:');
|
|
50
|
+
console.error(' npm install next');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
proc.on('exit', (code) => {
|
|
55
|
+
process.exit(code);
|
|
56
|
+
});
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent configuration - defines how an agent behaves
|
|
3
|
+
* All fields are optional as configuration may be partial
|
|
4
|
+
*/
|
|
5
|
+
interface AgentConfig {
|
|
6
|
+
/** Model identifier (e.g., 'claude-3-5-sonnet-20241022') */
|
|
7
|
+
model?: string;
|
|
8
|
+
/** Sampling temperature (0-2) */
|
|
9
|
+
temperature?: number;
|
|
10
|
+
/** Top-p sampling parameter (0-1) */
|
|
11
|
+
top_p?: number;
|
|
12
|
+
/** Maximum tokens per response */
|
|
13
|
+
max_tokens?: number;
|
|
14
|
+
/** System prompt override for this agent */
|
|
15
|
+
system?: string;
|
|
16
|
+
/** Additional model-specific parameters */
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Category configuration - defines model settings for task categories
|
|
21
|
+
* Categories are used by task() to select appropriate models
|
|
22
|
+
* All fields are optional as configuration may be partial
|
|
23
|
+
*/
|
|
24
|
+
interface CategoryConfig {
|
|
25
|
+
/** Model identifier (e.g., 'google/gemini-3.1-pro') */
|
|
26
|
+
model?: string;
|
|
27
|
+
/** Model variant (e.g., 'max', 'high', 'medium', 'low', 'xhigh') */
|
|
28
|
+
variant?: string;
|
|
29
|
+
/** Sampling temperature (0-2) */
|
|
30
|
+
temperature?: number;
|
|
31
|
+
/** Top-p sampling parameter (0-1) */
|
|
32
|
+
top_p?: number;
|
|
33
|
+
/** Additional system prompt to append */
|
|
34
|
+
prompt_append?: string;
|
|
35
|
+
/** Human-readable description */
|
|
36
|
+
description?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* OhMyOpencode configuration
|
|
40
|
+
* Root configuration object for oh-my-opencode
|
|
41
|
+
* All fields are optional as configuration may be partial
|
|
42
|
+
*/
|
|
43
|
+
interface OhMyOpencodeConfig {
|
|
44
|
+
/** Global agent configurations keyed by agent name */
|
|
45
|
+
agents?: Record<string, AgentConfig>;
|
|
46
|
+
/** Category configurations for task type model selection */
|
|
47
|
+
categories?: Record<string, CategoryConfig>;
|
|
48
|
+
/** Default agent configuration to use as base */
|
|
49
|
+
defaultAgent?: AgentConfig;
|
|
50
|
+
/** Project-specific settings */
|
|
51
|
+
project?: {
|
|
52
|
+
/** Project name */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Working directory */
|
|
55
|
+
cwd?: string;
|
|
56
|
+
};
|
|
57
|
+
/** Runtime configuration */
|
|
58
|
+
runtime?: {
|
|
59
|
+
/** Enable/disable features */
|
|
60
|
+
features?: {
|
|
61
|
+
/** Enable auto-approval for safe operations */
|
|
62
|
+
autoApprove?: boolean;
|
|
63
|
+
/** Enable verbose logging */
|
|
64
|
+
verbose?: boolean;
|
|
65
|
+
/** Enable debug mode */
|
|
66
|
+
debug?: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Maximum retry attempts */
|
|
69
|
+
maxRetries?: number;
|
|
70
|
+
/** Request timeout in milliseconds */
|
|
71
|
+
timeout?: number;
|
|
72
|
+
};
|
|
73
|
+
/** Tool-specific configurations */
|
|
74
|
+
tools?: Record<string, unknown>;
|
|
75
|
+
/** Custom environment variables */
|
|
76
|
+
env?: Record<string, string>;
|
|
77
|
+
/** Additional custom configuration */
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Profile configuration - defines agent and category settings for a profile
|
|
82
|
+
* Profiles allow switching between different agent/category configurations
|
|
83
|
+
*/
|
|
84
|
+
interface ProfileConfig {
|
|
85
|
+
/** Agent configurations keyed by agent name */
|
|
86
|
+
agents: Record<string, AgentConfig>;
|
|
87
|
+
/** Category configurations for task type model selection */
|
|
88
|
+
categories?: Record<string, CategoryConfig>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Profile - represents a named configuration profile
|
|
92
|
+
* Profiles can be built-in or user-created
|
|
93
|
+
*/
|
|
94
|
+
interface Profile {
|
|
95
|
+
/** Unique identifier */
|
|
96
|
+
id: string;
|
|
97
|
+
/** Human-readable name */
|
|
98
|
+
name: string;
|
|
99
|
+
/** Emoji icon for display */
|
|
100
|
+
emoji: string;
|
|
101
|
+
/** Optional description */
|
|
102
|
+
description?: string;
|
|
103
|
+
/** Creation timestamp */
|
|
104
|
+
createdAt: string;
|
|
105
|
+
/** Last update timestamp */
|
|
106
|
+
updatedAt: string;
|
|
107
|
+
/** Whether this is a default system profile */
|
|
108
|
+
isDefault?: boolean;
|
|
109
|
+
/** Whether this is a built-in profile that cannot be deleted */
|
|
110
|
+
isBuiltIn?: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Profile index - tracks all profiles and active selection
|
|
114
|
+
* This is the top-level structure for profile management
|
|
115
|
+
*/
|
|
116
|
+
interface ProfileIndex {
|
|
117
|
+
/** Schema version for migrations */
|
|
118
|
+
version: number;
|
|
119
|
+
/** All available profiles */
|
|
120
|
+
profiles: Profile[];
|
|
121
|
+
/** Currently active profile ID */
|
|
122
|
+
activeProfileId: string | null;
|
|
123
|
+
/** Last modification timestamp */
|
|
124
|
+
lastModified: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare const CONFIG_DIR: string;
|
|
128
|
+
declare const CONFIG_PATH: string;
|
|
129
|
+
type OpenCodeConfig = {
|
|
130
|
+
agents?: Record<string, unknown>;
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
};
|
|
133
|
+
declare function detectConfig(configPath?: string): boolean;
|
|
134
|
+
declare function readConfig(configPath?: string): Promise<OpenCodeConfig>;
|
|
135
|
+
declare function writeConfig(config: OpenCodeConfig, configPath?: string): Promise<void>;
|
|
136
|
+
|
|
137
|
+
export { type AgentConfig, CONFIG_DIR, CONFIG_PATH, type CategoryConfig, type OhMyOpencodeConfig, type OpenCodeConfig, type Profile, type ProfileConfig, type ProfileIndex, detectConfig, readConfig, writeConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent configuration - defines how an agent behaves
|
|
3
|
+
* All fields are optional as configuration may be partial
|
|
4
|
+
*/
|
|
5
|
+
interface AgentConfig {
|
|
6
|
+
/** Model identifier (e.g., 'claude-3-5-sonnet-20241022') */
|
|
7
|
+
model?: string;
|
|
8
|
+
/** Sampling temperature (0-2) */
|
|
9
|
+
temperature?: number;
|
|
10
|
+
/** Top-p sampling parameter (0-1) */
|
|
11
|
+
top_p?: number;
|
|
12
|
+
/** Maximum tokens per response */
|
|
13
|
+
max_tokens?: number;
|
|
14
|
+
/** System prompt override for this agent */
|
|
15
|
+
system?: string;
|
|
16
|
+
/** Additional model-specific parameters */
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Category configuration - defines model settings for task categories
|
|
21
|
+
* Categories are used by task() to select appropriate models
|
|
22
|
+
* All fields are optional as configuration may be partial
|
|
23
|
+
*/
|
|
24
|
+
interface CategoryConfig {
|
|
25
|
+
/** Model identifier (e.g., 'google/gemini-3.1-pro') */
|
|
26
|
+
model?: string;
|
|
27
|
+
/** Model variant (e.g., 'max', 'high', 'medium', 'low', 'xhigh') */
|
|
28
|
+
variant?: string;
|
|
29
|
+
/** Sampling temperature (0-2) */
|
|
30
|
+
temperature?: number;
|
|
31
|
+
/** Top-p sampling parameter (0-1) */
|
|
32
|
+
top_p?: number;
|
|
33
|
+
/** Additional system prompt to append */
|
|
34
|
+
prompt_append?: string;
|
|
35
|
+
/** Human-readable description */
|
|
36
|
+
description?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* OhMyOpencode configuration
|
|
40
|
+
* Root configuration object for oh-my-opencode
|
|
41
|
+
* All fields are optional as configuration may be partial
|
|
42
|
+
*/
|
|
43
|
+
interface OhMyOpencodeConfig {
|
|
44
|
+
/** Global agent configurations keyed by agent name */
|
|
45
|
+
agents?: Record<string, AgentConfig>;
|
|
46
|
+
/** Category configurations for task type model selection */
|
|
47
|
+
categories?: Record<string, CategoryConfig>;
|
|
48
|
+
/** Default agent configuration to use as base */
|
|
49
|
+
defaultAgent?: AgentConfig;
|
|
50
|
+
/** Project-specific settings */
|
|
51
|
+
project?: {
|
|
52
|
+
/** Project name */
|
|
53
|
+
name?: string;
|
|
54
|
+
/** Working directory */
|
|
55
|
+
cwd?: string;
|
|
56
|
+
};
|
|
57
|
+
/** Runtime configuration */
|
|
58
|
+
runtime?: {
|
|
59
|
+
/** Enable/disable features */
|
|
60
|
+
features?: {
|
|
61
|
+
/** Enable auto-approval for safe operations */
|
|
62
|
+
autoApprove?: boolean;
|
|
63
|
+
/** Enable verbose logging */
|
|
64
|
+
verbose?: boolean;
|
|
65
|
+
/** Enable debug mode */
|
|
66
|
+
debug?: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Maximum retry attempts */
|
|
69
|
+
maxRetries?: number;
|
|
70
|
+
/** Request timeout in milliseconds */
|
|
71
|
+
timeout?: number;
|
|
72
|
+
};
|
|
73
|
+
/** Tool-specific configurations */
|
|
74
|
+
tools?: Record<string, unknown>;
|
|
75
|
+
/** Custom environment variables */
|
|
76
|
+
env?: Record<string, string>;
|
|
77
|
+
/** Additional custom configuration */
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Profile configuration - defines agent and category settings for a profile
|
|
82
|
+
* Profiles allow switching between different agent/category configurations
|
|
83
|
+
*/
|
|
84
|
+
interface ProfileConfig {
|
|
85
|
+
/** Agent configurations keyed by agent name */
|
|
86
|
+
agents: Record<string, AgentConfig>;
|
|
87
|
+
/** Category configurations for task type model selection */
|
|
88
|
+
categories?: Record<string, CategoryConfig>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Profile - represents a named configuration profile
|
|
92
|
+
* Profiles can be built-in or user-created
|
|
93
|
+
*/
|
|
94
|
+
interface Profile {
|
|
95
|
+
/** Unique identifier */
|
|
96
|
+
id: string;
|
|
97
|
+
/** Human-readable name */
|
|
98
|
+
name: string;
|
|
99
|
+
/** Emoji icon for display */
|
|
100
|
+
emoji: string;
|
|
101
|
+
/** Optional description */
|
|
102
|
+
description?: string;
|
|
103
|
+
/** Creation timestamp */
|
|
104
|
+
createdAt: string;
|
|
105
|
+
/** Last update timestamp */
|
|
106
|
+
updatedAt: string;
|
|
107
|
+
/** Whether this is a default system profile */
|
|
108
|
+
isDefault?: boolean;
|
|
109
|
+
/** Whether this is a built-in profile that cannot be deleted */
|
|
110
|
+
isBuiltIn?: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Profile index - tracks all profiles and active selection
|
|
114
|
+
* This is the top-level structure for profile management
|
|
115
|
+
*/
|
|
116
|
+
interface ProfileIndex {
|
|
117
|
+
/** Schema version for migrations */
|
|
118
|
+
version: number;
|
|
119
|
+
/** All available profiles */
|
|
120
|
+
profiles: Profile[];
|
|
121
|
+
/** Currently active profile ID */
|
|
122
|
+
activeProfileId: string | null;
|
|
123
|
+
/** Last modification timestamp */
|
|
124
|
+
lastModified: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare const CONFIG_DIR: string;
|
|
128
|
+
declare const CONFIG_PATH: string;
|
|
129
|
+
type OpenCodeConfig = {
|
|
130
|
+
agents?: Record<string, unknown>;
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
};
|
|
133
|
+
declare function detectConfig(configPath?: string): boolean;
|
|
134
|
+
declare function readConfig(configPath?: string): Promise<OpenCodeConfig>;
|
|
135
|
+
declare function writeConfig(config: OpenCodeConfig, configPath?: string): Promise<void>;
|
|
136
|
+
|
|
137
|
+
export { type AgentConfig, CONFIG_DIR, CONFIG_PATH, type CategoryConfig, type OhMyOpencodeConfig, type OpenCodeConfig, type Profile, type ProfileConfig, type ProfileIndex, detectConfig, readConfig, writeConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CONFIG_DIR: () => CONFIG_DIR,
|
|
24
|
+
CONFIG_PATH: () => CONFIG_PATH,
|
|
25
|
+
detectConfig: () => detectConfig,
|
|
26
|
+
readConfig: () => readConfig,
|
|
27
|
+
writeConfig: () => writeConfig
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/lib/opencodeConfig.ts
|
|
32
|
+
var import_promises = require("fs/promises");
|
|
33
|
+
var import_fs = require("fs");
|
|
34
|
+
var import_path = require("path");
|
|
35
|
+
var import_os = require("os");
|
|
36
|
+
var import_comment_json = require("comment-json");
|
|
37
|
+
var CONFIG_DIR = (0, import_path.join)((0, import_os.homedir)(), ".config", "opencode");
|
|
38
|
+
var CONFIG_PATH = (0, import_path.join)(CONFIG_DIR, "oh-my-opencode.json");
|
|
39
|
+
function detectConfig(configPath = CONFIG_PATH) {
|
|
40
|
+
try {
|
|
41
|
+
return (0, import_fs.existsSync)(configPath);
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function readConfig(configPath = CONFIG_PATH) {
|
|
47
|
+
try {
|
|
48
|
+
const content = await (0, import_promises.readFile)(configPath, "utf-8");
|
|
49
|
+
const config = (0, import_comment_json.parse)(content, null, false);
|
|
50
|
+
return config;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function writeConfig(config, configPath = CONFIG_PATH) {
|
|
56
|
+
try {
|
|
57
|
+
const configDir = (0, import_path.join)(configPath, "..");
|
|
58
|
+
if (!(0, import_fs.existsSync)(configDir)) {
|
|
59
|
+
(0, import_fs.mkdirSync)(configDir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
const content = (0, import_comment_json.stringify)(config, null, 2);
|
|
62
|
+
await (0, import_promises.writeFile)(configPath, content, "utf-8");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
throw new Error(`Failed to write config: ${error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
68
|
+
0 && (module.exports = {
|
|
69
|
+
CONFIG_DIR,
|
|
70
|
+
CONFIG_PATH,
|
|
71
|
+
detectConfig,
|
|
72
|
+
readConfig,
|
|
73
|
+
writeConfig
|
|
74
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/lib/opencodeConfig.ts
|
|
2
|
+
import { readFile, writeFile } from "fs/promises";
|
|
3
|
+
import { existsSync, mkdirSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
import { parse, stringify } from "comment-json";
|
|
7
|
+
var CONFIG_DIR = join(homedir(), ".config", "opencode");
|
|
8
|
+
var CONFIG_PATH = join(CONFIG_DIR, "oh-my-opencode.json");
|
|
9
|
+
function detectConfig(configPath = CONFIG_PATH) {
|
|
10
|
+
try {
|
|
11
|
+
return existsSync(configPath);
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function readConfig(configPath = CONFIG_PATH) {
|
|
17
|
+
try {
|
|
18
|
+
const content = await readFile(configPath, "utf-8");
|
|
19
|
+
const config = parse(content, null, false);
|
|
20
|
+
return config;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function writeConfig(config, configPath = CONFIG_PATH) {
|
|
26
|
+
try {
|
|
27
|
+
const configDir = join(configPath, "..");
|
|
28
|
+
if (!existsSync(configDir)) {
|
|
29
|
+
mkdirSync(configDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
const content = stringify(config, null, 2);
|
|
32
|
+
await writeFile(configPath, content, "utf-8");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to write config: ${error}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
CONFIG_DIR,
|
|
39
|
+
CONFIG_PATH,
|
|
40
|
+
detectConfig,
|
|
41
|
+
readConfig,
|
|
42
|
+
writeConfig
|
|
43
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vibepulse",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Real-time dashboard for monitoring and managing OpenCode sessions",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ChatTreeNet/VibePulse"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"bin",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"require": "./dist/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"next": ">=14.0.0",
|
|
27
|
+
"react": ">=18.0.0",
|
|
28
|
+
"react-dom": ">=18.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"next": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "next dev -p 3456",
|
|
37
|
+
"build": "next build",
|
|
38
|
+
"start": "next start -p 3456",
|
|
39
|
+
"lint": "eslint",
|
|
40
|
+
"test": "vitest",
|
|
41
|
+
"test:run": "vitest run",
|
|
42
|
+
"build:lib": "tsup src/index.ts --format cjs,esm --dts --clean --outDir dist --external react,react-dom,next --tsconfig tsconfig.lib.json"
|
|
43
|
+
},
|
|
44
|
+
"bin": {
|
|
45
|
+
"vibepulse": "./bin/vibepulse.js"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@dnd-kit/core": "^6.3.1",
|
|
49
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
50
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
51
|
+
"@opencode-ai/sdk": "^1.2.15",
|
|
52
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
53
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
54
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
55
|
+
"@tanstack/react-query": "^5.90.21",
|
|
56
|
+
"clsx": "^2.1.1",
|
|
57
|
+
"comment-json": "^4.6.2",
|
|
58
|
+
"lucide-react": "^0.575.0",
|
|
59
|
+
"react-hook-form": "^7.71.2",
|
|
60
|
+
"tailwind-merge": "^3.5.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@tailwindcss/postcss": "^4",
|
|
64
|
+
"@testing-library/dom": "^10.4.1",
|
|
65
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
66
|
+
"@testing-library/react": "^16.3.0",
|
|
67
|
+
"@testing-library/user-event": "^14.6.1",
|
|
68
|
+
"@types/node": "^20",
|
|
69
|
+
"@types/react": "^19",
|
|
70
|
+
"@types/react-dom": "^19",
|
|
71
|
+
"@vitejs/plugin-react": "^4.5.2",
|
|
72
|
+
"esbuild-plugin-alias": "^0.2.1",
|
|
73
|
+
"eslint": "^9",
|
|
74
|
+
"eslint-config-next": "16.1.6",
|
|
75
|
+
"jsdom": "^26.1.0",
|
|
76
|
+
"tailwindcss": "^4",
|
|
77
|
+
"tsup": "^8.5.1",
|
|
78
|
+
"typescript": "^5",
|
|
79
|
+
"vitest": "^3.2.4"
|
|
80
|
+
}
|
|
81
|
+
}
|