dmux 3.0.2 → 3.1.1
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/dist/DmuxApp.d.ts.map +1 -1
- package/dist/DmuxApp.js +242 -23
- package/dist/DmuxApp.js.map +1 -1
- package/dist/PaneAnalyzer.d.ts +0 -4
- package/dist/PaneAnalyzer.d.ts.map +1 -1
- package/dist/PaneAnalyzer.js +2 -17
- package/dist/PaneAnalyzer.js.map +1 -1
- package/dist/_plugin-vue_export-helper.css +1 -1
- package/dist/actions/paneActions.d.ts.map +1 -1
- package/dist/actions/paneActions.js +94 -40
- package/dist/actions/paneActions.js.map +1 -1
- package/dist/components/ActionConfirmDialog.js +1 -1
- package/dist/components/ActionConfirmDialog.js.map +1 -1
- package/dist/components/CloseOptionsDialog.d.ts.map +1 -1
- package/dist/components/CloseOptionsDialog.js +9 -7
- package/dist/components/CloseOptionsDialog.js.map +1 -1
- package/dist/components/FooterHelp.js +1 -1
- package/dist/components/FooterHelp.js.map +1 -1
- package/dist/components/HooksDialog.d.ts +12 -0
- package/dist/components/HooksDialog.d.ts.map +1 -0
- package/dist/components/HooksDialog.js +52 -0
- package/dist/components/HooksDialog.js.map +1 -0
- package/dist/components/MergeConfirmationDialog.d.ts.map +1 -1
- package/dist/components/MergeConfirmationDialog.js +2 -1
- package/dist/components/MergeConfirmationDialog.js.map +1 -1
- package/dist/components/NewPaneDialog.d.ts.map +1 -1
- package/dist/components/NewPaneDialog.js +1 -3
- package/dist/components/NewPaneDialog.js.map +1 -1
- package/dist/components/SettingsDialog.d.ts +16 -0
- package/dist/components/SettingsDialog.d.ts.map +1 -0
- package/dist/components/SettingsDialog.js +95 -0
- package/dist/components/SettingsDialog.js.map +1 -0
- package/dist/dashboard.js +2 -2
- package/dist/hooks/useAutoUpdater.js +2 -2
- package/dist/hooks/useAutoUpdater.js.map +1 -1
- package/dist/hooks/usePaneCreation.d.ts.map +1 -1
- package/dist/hooks/usePaneCreation.js +22 -3
- package/dist/hooks/usePaneCreation.js.map +1 -1
- package/dist/hooks/usePanes.js +2 -2
- package/dist/hooks/usePanes.js.map +1 -1
- package/dist/hooks/useTerminalWidth.d.ts.map +1 -1
- package/dist/hooks/useTerminalWidth.js +5 -0
- package/dist/hooks/useTerminalWidth.js.map +1 -1
- package/dist/hooks/useWorktreeActions.js +4 -4
- package/dist/hooks/useWorktreeActions.js.map +1 -1
- package/dist/server/embedded-assets.d.ts.map +1 -1
- package/dist/server/embedded-assets.js +251 -47
- package/dist/server/embedded-assets.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +195 -55
- package/dist/server/routes.js.map +1 -1
- package/dist/services/ConfigWatcher.d.ts +9 -0
- package/dist/services/ConfigWatcher.d.ts.map +1 -1
- package/dist/services/ConfigWatcher.js +17 -0
- package/dist/services/ConfigWatcher.js.map +1 -1
- package/dist/services/StatusDetector.js +7 -7
- package/dist/services/StatusDetector.js.map +1 -1
- package/dist/services/TunnelService.d.ts.map +1 -1
- package/dist/services/TunnelService.js +25 -3
- package/dist/services/TunnelService.js.map +1 -1
- package/dist/shared/StateManager.d.ts +11 -0
- package/dist/shared/StateManager.d.ts.map +1 -1
- package/dist/shared/StateManager.js +26 -0
- package/dist/shared/StateManager.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/conflictResolutionPane.d.ts.map +1 -1
- package/dist/utils/conflictResolutionPane.js +3 -2
- package/dist/utils/conflictResolutionPane.js.map +1 -1
- package/dist/utils/generated-agents-doc.d.ts +6 -0
- package/dist/utils/generated-agents-doc.d.ts.map +1 -0
- package/dist/utils/generated-agents-doc.js +430 -0
- package/dist/utils/generated-agents-doc.js.map +1 -0
- package/dist/utils/hooks.d.ts +70 -0
- package/dist/utils/hooks.d.ts.map +1 -0
- package/dist/utils/hooks.js +216 -0
- package/dist/utils/hooks.js.map +1 -0
- package/dist/utils/hooksDocs.d.ts +42 -0
- package/dist/utils/hooksDocs.d.ts.map +1 -0
- package/dist/utils/hooksDocs.js +325 -0
- package/dist/utils/hooksDocs.js.map +1 -0
- package/dist/utils/paneCapture.d.ts +21 -0
- package/dist/utils/paneCapture.d.ts.map +1 -0
- package/dist/utils/paneCapture.js +96 -0
- package/dist/utils/paneCapture.js.map +1 -0
- package/dist/utils/paneCreation.d.ts +1 -0
- package/dist/utils/paneCreation.d.ts.map +1 -1
- package/dist/utils/paneCreation.js +90 -18
- package/dist/utils/paneCreation.js.map +1 -1
- package/dist/utils/settingsManager.d.ts +49 -0
- package/dist/utils/settingsManager.d.ts.map +1 -0
- package/dist/utils/settingsManager.js +172 -0
- package/dist/utils/settingsManager.js.map +1 -0
- package/dist/utils/tmux.d.ts.map +1 -1
- package/dist/utils/tmux.js +79 -20
- package/dist/utils/tmux.js.map +1 -1
- package/dist/workers/PaneWorker.js +3 -6
- package/dist/workers/PaneWorker.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks System
|
|
3
|
+
*
|
|
4
|
+
* Executes user-defined scripts at key lifecycle events.
|
|
5
|
+
* Hook scripts are stored in .dmux/hooks/ and receive context via environment variables.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync, spawn } from 'child_process';
|
|
8
|
+
import { existsSync, accessSync, constants, mkdirSync, writeFileSync } from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import { HOOKS_DOCUMENTATION, HOOKS_README, EXAMPLE_HOOKS } from './hooksDocs.js';
|
|
12
|
+
/**
|
|
13
|
+
* Find a hook script with priority resolution:
|
|
14
|
+
* 1. .dmux-hooks/ (version controlled, team hooks)
|
|
15
|
+
* 2. .dmux/hooks/ (gitignored, local overrides)
|
|
16
|
+
* 3. ~/.dmux/hooks/ (global user hooks)
|
|
17
|
+
*/
|
|
18
|
+
export function findHook(projectRoot, hookName) {
|
|
19
|
+
const searchPaths = [
|
|
20
|
+
path.join(projectRoot, '.dmux-hooks', hookName), // Team hooks (VC)
|
|
21
|
+
path.join(projectRoot, '.dmux', 'hooks', hookName), // Local override
|
|
22
|
+
path.join(os.homedir(), '.dmux', 'hooks', hookName), // Global hooks
|
|
23
|
+
];
|
|
24
|
+
for (const hookPath of searchPaths) {
|
|
25
|
+
if (existsSync(hookPath)) {
|
|
26
|
+
try {
|
|
27
|
+
// Check if file is executable
|
|
28
|
+
accessSync(hookPath, constants.X_OK);
|
|
29
|
+
return hookPath;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
console.error(`[Hooks] Warning: Hook "${hookName}" exists at ${hookPath} but is not executable. Run: chmod +x ${hookPath}`);
|
|
33
|
+
// Continue searching other locations
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build environment variables for a hook
|
|
41
|
+
*/
|
|
42
|
+
export async function buildHookEnvironment(projectRoot, pane, extraData) {
|
|
43
|
+
const env = {
|
|
44
|
+
DMUX_ROOT: projectRoot,
|
|
45
|
+
...process.env, // Inherit parent environment
|
|
46
|
+
};
|
|
47
|
+
// Add server port if available
|
|
48
|
+
const { StateManager } = await import('../shared/StateManager.js');
|
|
49
|
+
const state = StateManager.getInstance().getState();
|
|
50
|
+
if (state.serverPort) {
|
|
51
|
+
env.DMUX_SERVER_PORT = String(state.serverPort);
|
|
52
|
+
}
|
|
53
|
+
// Add pane-specific data
|
|
54
|
+
if (pane) {
|
|
55
|
+
env.DMUX_PANE_ID = pane.id;
|
|
56
|
+
env.DMUX_SLUG = pane.slug;
|
|
57
|
+
env.DMUX_PROMPT = pane.prompt;
|
|
58
|
+
env.DMUX_AGENT = pane.agent || 'unknown';
|
|
59
|
+
env.DMUX_TMUX_PANE_ID = pane.paneId;
|
|
60
|
+
if (pane.worktreePath) {
|
|
61
|
+
env.DMUX_WORKTREE_PATH = pane.worktreePath;
|
|
62
|
+
env.DMUX_BRANCH = pane.slug; // Branch name matches slug
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Add any extra data
|
|
66
|
+
if (extraData) {
|
|
67
|
+
Object.assign(env, extraData);
|
|
68
|
+
}
|
|
69
|
+
return env;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Execute a hook script asynchronously
|
|
73
|
+
*
|
|
74
|
+
* Hooks run in the background and don't block dmux operations.
|
|
75
|
+
* Errors are logged but don't crash the application.
|
|
76
|
+
*/
|
|
77
|
+
export async function triggerHook(hookName, projectRoot, pane, extraData) {
|
|
78
|
+
// Initialize hooks directory on first use (lazy init)
|
|
79
|
+
initializeHooksDirectory(projectRoot);
|
|
80
|
+
const hookPath = findHook(projectRoot, hookName);
|
|
81
|
+
if (!hookPath) {
|
|
82
|
+
// No hook script found, that's fine
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Build environment
|
|
86
|
+
const env = await buildHookEnvironment(projectRoot, pane, extraData);
|
|
87
|
+
// Log hook execution
|
|
88
|
+
console.error(`[Hooks] Executing ${hookName} hook: ${hookPath}`);
|
|
89
|
+
try {
|
|
90
|
+
// Spawn hook process in background
|
|
91
|
+
const child = spawn(hookPath, [], {
|
|
92
|
+
env: env,
|
|
93
|
+
cwd: projectRoot,
|
|
94
|
+
detached: true,
|
|
95
|
+
stdio: 'ignore', // Don't capture output by default
|
|
96
|
+
});
|
|
97
|
+
// Detach so the hook can run independently
|
|
98
|
+
child.unref();
|
|
99
|
+
// Optional: Log when hook completes (but don't wait for it)
|
|
100
|
+
child.on('exit', (code) => {
|
|
101
|
+
if (code === 0) {
|
|
102
|
+
console.error(`[Hooks] ${hookName} completed successfully`);
|
|
103
|
+
}
|
|
104
|
+
else if (code !== null) {
|
|
105
|
+
console.error(`[Hooks] ${hookName} exited with code ${code}`);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
child.on('error', (error) => {
|
|
109
|
+
console.error(`[Hooks] ${hookName} failed to start: ${error.message}`);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error(`[Hooks] Failed to execute ${hookName}: ${error}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Execute a hook synchronously (blocking)
|
|
118
|
+
*
|
|
119
|
+
* Use sparingly - only for hooks that MUST complete before proceeding.
|
|
120
|
+
* Most hooks should use triggerHook() instead.
|
|
121
|
+
*/
|
|
122
|
+
export async function triggerHookSync(hookName, projectRoot, pane, extraData, timeoutMs = 30000) {
|
|
123
|
+
const hookPath = findHook(projectRoot, hookName);
|
|
124
|
+
if (!hookPath) {
|
|
125
|
+
return { success: true }; // No hook = success
|
|
126
|
+
}
|
|
127
|
+
const env = await buildHookEnvironment(projectRoot, pane, extraData);
|
|
128
|
+
console.error(`[Hooks] Executing ${hookName} hook (sync): ${hookPath}`);
|
|
129
|
+
try {
|
|
130
|
+
const output = execSync(hookPath, {
|
|
131
|
+
env: env,
|
|
132
|
+
cwd: projectRoot,
|
|
133
|
+
encoding: 'utf-8',
|
|
134
|
+
timeout: timeoutMs,
|
|
135
|
+
stdio: 'pipe',
|
|
136
|
+
});
|
|
137
|
+
console.error(`[Hooks] ${hookName} completed successfully`);
|
|
138
|
+
return { success: true, output };
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
const errorMsg = error.message || String(error);
|
|
142
|
+
console.error(`[Hooks] ${hookName} failed: ${errorMsg}`);
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: errorMsg,
|
|
146
|
+
output: error.stdout?.toString() || '',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if a hook exists for a given hook type
|
|
152
|
+
*/
|
|
153
|
+
export function hasHook(projectRoot, hookName) {
|
|
154
|
+
return findHook(projectRoot, hookName) !== null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* List all available hooks in the project
|
|
158
|
+
*/
|
|
159
|
+
export function listAvailableHooks(projectRoot) {
|
|
160
|
+
const allHooks = [
|
|
161
|
+
'before_pane_create',
|
|
162
|
+
'pane_created',
|
|
163
|
+
'worktree_created',
|
|
164
|
+
'before_pane_close',
|
|
165
|
+
'pane_closed',
|
|
166
|
+
'before_worktree_remove',
|
|
167
|
+
'worktree_removed',
|
|
168
|
+
'pre_merge',
|
|
169
|
+
'post_merge',
|
|
170
|
+
'run_test',
|
|
171
|
+
'run_dev',
|
|
172
|
+
];
|
|
173
|
+
return allHooks.filter((hook) => hasHook(projectRoot, hook));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Initialize .dmux-hooks/ directory with documentation and examples
|
|
177
|
+
* This gets called the first time hooks are accessed or when user explicitly initializes
|
|
178
|
+
*/
|
|
179
|
+
export function initializeHooksDirectory(projectRoot) {
|
|
180
|
+
const hooksDir = path.join(projectRoot, '.dmux-hooks');
|
|
181
|
+
// Skip if already initialized
|
|
182
|
+
if (existsSync(path.join(hooksDir, 'AGENTS.md'))) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
console.error('[Hooks] Initializing .dmux-hooks/ directory...');
|
|
186
|
+
// Create main hooks directory
|
|
187
|
+
if (!existsSync(hooksDir)) {
|
|
188
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
// Write AGENTS.md (complete reference)
|
|
191
|
+
writeFileSync(path.join(hooksDir, 'AGENTS.md'), HOOKS_DOCUMENTATION, 'utf-8');
|
|
192
|
+
// Write CLAUDE.md (identical to AGENTS.md, just different filename for Claude Code)
|
|
193
|
+
writeFileSync(path.join(hooksDir, 'CLAUDE.md'), HOOKS_DOCUMENTATION, 'utf-8');
|
|
194
|
+
// Write README.md
|
|
195
|
+
writeFileSync(path.join(hooksDir, 'README.md'), HOOKS_README, 'utf-8');
|
|
196
|
+
// Create examples directory
|
|
197
|
+
const examplesDir = path.join(hooksDir, 'examples');
|
|
198
|
+
if (!existsSync(examplesDir)) {
|
|
199
|
+
mkdirSync(examplesDir, { recursive: true });
|
|
200
|
+
}
|
|
201
|
+
// Write example hooks
|
|
202
|
+
for (const [filename, content] of Object.entries(EXAMPLE_HOOKS)) {
|
|
203
|
+
const examplePath = path.join(examplesDir, filename);
|
|
204
|
+
writeFileSync(examplePath, content, 'utf-8');
|
|
205
|
+
// Make examples executable
|
|
206
|
+
try {
|
|
207
|
+
execSync(`chmod +x "${examplePath}"`, { stdio: 'pipe' });
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Ignore chmod errors (Windows, etc.)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
console.error('[Hooks] ✅ Initialized .dmux-hooks/ with documentation and examples');
|
|
214
|
+
console.error('[Hooks] 📝 Read AGENTS.md or CLAUDE.md to get started');
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/utils/hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded Hooks Documentation
|
|
3
|
+
*
|
|
4
|
+
* This file contains all documentation that gets written to .dmux-hooks/
|
|
5
|
+
* when the directory is initialized. The AGENTS_MD content is auto-generated
|
|
6
|
+
* and imported from generated-agents-doc.ts
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Main documentation - gets written as both AGENTS.md and CLAUDE.md
|
|
10
|
+
* Different agents look for different filenames, but content is identical
|
|
11
|
+
*/
|
|
12
|
+
export declare const HOOKS_DOCUMENTATION = "# dmux Hooks System - Agent Reference\n\n**Auto-generated documentation for AI agents**\n\nThis document contains everything an AI agent needs to create, modify, and understand dmux hooks. It is automatically generated from the dmux source code and embedded in the binary.\n\n## What You're Working On\n\nYou are editing hooks for **dmux**, a tmux pane manager that creates AI-powered development workflows. Each pane runs in its own git worktree with an AI agent (Claude Code or opencode).\n\n## Your Goal\n\nCreate executable bash scripts in `.dmux-hooks/` that run automatically at key lifecycle events.\n\n## Quick Start\n\n1. **Create a hook file**: `touch .dmux-hooks/worktree_created`\n2. **Make it executable**: `chmod +x .dmux-hooks/worktree_created`\n3. **Add shebang**: Start with `#!/bin/bash`\n4. **Use environment variables**: Access `$DMUX_ROOT`, `$DMUX_WORKTREE_PATH`, etc.\n5. **Test it**: Set env vars manually and run the script\n\n## Hook Execution Model\n\n- **Non-blocking**: Hooks run in background (detached processes)\n- **Silent failures**: Hook errors are logged but don't stop dmux\n- **Environment-based**: All context passed via environment variables\n- **Version controlled**: Hooks in `.dmux-hooks/` are shared with team\n- **Priority resolution**: `.dmux-hooks/` \u2192 `.dmux/hooks/` \u2192 `~/.dmux/hooks/`\n\n## Available Hooks\n\n### Pane Lifecycle Hooks\n\n| Hook | When | Common Use Cases |\n|------|------|------------------|\n| `before_pane_create` | Before pane creation | Validation, notifications, pre-flight checks |\n| `pane_created` | After pane, before worktree | Configure tmux settings, prepare environment |\n| `worktree_created` | After full setup | Install deps, copy configs, setup git |\n| `before_pane_close` | Before closing | Save state, backup uncommitted work |\n| `pane_closed` | After closed | Cleanup resources, analytics, notifications |\n\n### Worktree Lifecycle Hooks\n\n| Hook | When | Common Use Cases |\n|------|------|------------------|\n| `before_worktree_remove` | Before worktree removal | Archive worktree, save artifacts |\n| `worktree_removed` | After worktree removed | Cleanup external references |\n\n### Merge Lifecycle Hooks\n\n| Hook | When | Common Use Cases |\n|------|------|------------------|\n| `pre_merge` | Before merge operation | Run final tests, create backups |\n| `post_merge` | After successful merge | Deploy, close issues, notify team |\n\n### Interactive Hooks (with HTTP callbacks)\n\n| Hook | When | Common Use Cases |\n|------|------|------------------|\n| `run_test` | When tests triggered | Run test suite, report status via HTTP |\n| `run_dev` | When dev server triggered | Start dev server, create tunnel, report URL |\n\n\n## Environment Variables\n\n### Always Available\n```bash\nDMUX_ROOT=\"/path/to/project\" # Project root directory\nDMUX_SERVER_PORT=\"3142\" # HTTP server port\n```\n\n### Pane Context (most hooks)\n```bash\nDMUX_PANE_ID=\"dmux-1234567890\" # dmux pane identifier\nDMUX_SLUG=\"fix-auth-bug\" # Branch/worktree name\nDMUX_PROMPT=\"Fix authentication bug\" # User's prompt\nDMUX_AGENT=\"claude\" # Agent type (claude|opencode)\nDMUX_TMUX_PANE_ID=\"%38\" # tmux pane ID\n```\n\n### Worktree Context\n```bash\nDMUX_WORKTREE_PATH=\"/path/.dmux/worktrees/fix-auth-bug\"\nDMUX_BRANCH=\"fix-auth-bug\" # Same as slug\n```\n\n### Merge Context\n```bash\nDMUX_TARGET_BRANCH=\"main\" # Branch being merged into\n```\n\n## HTTP Callback API\n\nInteractive hooks (`run_test` and `run_dev`) can update dmux UI via HTTP.\n\n### Update Test Status\n```bash\ncurl -X PUT \"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test\" -H \"Content-Type: application/json\" -d '{\"status\": \"running\", \"output\": \"optional test output\"}'\n\n# Status values: \"running\" | \"passed\" | \"failed\"\n```\n\n### Update Dev Server\n```bash\ncurl -X PUT \"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev\" -H \"Content-Type: application/json\" -d '{\"status\": \"running\", \"url\": \"http://localhost:3000\"}'\n\n# Status values: \"running\" | \"stopped\"\n# url: Can be localhost or tunnel URL (ngrok, cloudflared, etc.)\n```\n\n## Common Patterns\n\n### Pattern 1: Install Dependencies\n```bash\n#!/bin/bash\n# .dmux-hooks/worktree_created\n\ncd \"$DMUX_WORKTREE_PATH\"\n\nif [ -f \"pnpm-lock.yaml\" ]; then\n pnpm install --prefer-offline &\nelif [ -f \"package-lock.json\" ]; then\n npm install &\nelif [ -f \"yarn.lock\" ]; then\n yarn install &\nelif [ -f \"Gemfile\" ]; then\n bundle install &\nelif [ -f \"requirements.txt\" ]; then\n pip install -r requirements.txt &\nelif [ -f \"Cargo.toml\" ]; then\n cargo build &\nfi\n```\n\n### Pattern 2: Copy Configuration\n```bash\n#!/bin/bash\n# .dmux-hooks/worktree_created\n\n# Copy environment file\nif [ -f \"$DMUX_ROOT/.env.local\" ]; then\n cp \"$DMUX_ROOT/.env.local\" \"$DMUX_WORKTREE_PATH/.env.local\"\nfi\n\n# Copy other config files\nfor file in .env.development .npmrc .yarnrc; do\n if [ -f \"$DMUX_ROOT/$file\" ]; then\n cp \"$DMUX_ROOT/$file\" \"$DMUX_WORKTREE_PATH/$file\"\n fi\ndone\n```\n\n### Pattern 3: Run Tests with Status Updates\n```bash\n#!/bin/bash\n# .dmux-hooks/run_test\n\nset -e\ncd \"$DMUX_WORKTREE_PATH\"\nAPI=\"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test\"\n\n# Update: starting\ncurl -s -X PUT \"$API\" -H \"Content-Type: application/json\" -d '{\"status\": \"running\"}' > /dev/null\n\n# Run tests and capture output\nOUTPUT_FILE=\"/tmp/dmux-test-$DMUX_PANE_ID.txt\"\nif pnpm test > \"$OUTPUT_FILE\" 2>&1; then\n STATUS=\"passed\"\nelse\n STATUS=\"failed\"\nfi\n\n# Get output (truncate if too long)\nOUTPUT=$(head -c 5000 \"$OUTPUT_FILE\")\n\n# Update: complete\ncurl -s -X PUT \"$API\" -H \"Content-Type: application/json\" -d \"$(jq -n --arg status \"$STATUS\" --arg output \"$OUTPUT\" '{status: $status, output: $output}')\" > /dev/null\n\nrm -f \"$OUTPUT_FILE\"\n```\n\n### Pattern 4: Dev Server with Tunnel\n```bash\n#!/bin/bash\n# .dmux-hooks/run_dev\n\nset -e\ncd \"$DMUX_WORKTREE_PATH\"\nAPI=\"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev\"\n\n# Start dev server in background\nLOG_FILE=\"/tmp/dmux-dev-$DMUX_PANE_ID.log\"\npnpm dev > \"$LOG_FILE\" 2>&1 &\nDEV_PID=$!\n\n# Wait for server to start\nsleep 5\n\n# Detect port from logs\nPORT=$(grep -oP 'localhost:Kd+' \"$LOG_FILE\" | head -1)\n[ -z \"$PORT\" ] && PORT=3000\n\n# Optional: Create tunnel with cloudflared\nif command -v cloudflared &> /dev/null; then\n TUNNEL=$(cloudflared tunnel --url \"http://localhost:$PORT\" 2>&1 | grep -oP 'https://[a-z0-9-]+.trycloudflare.com' | head -1)\n URL=\"${TUNNEL:-http://localhost:$PORT}\"\nelse\n URL=\"http://localhost:$PORT\"\nfi\n\n# Report status\ncurl -s -X PUT \"$API\" -H \"Content-Type: application/json\" -d \"{\"status\": \"running\", \"url\": \"$URL\"}\" > /dev/null\n\necho \"[Hook] Dev server running at $URL (PID: $DEV_PID)\"\n```\n\n### Pattern 5: Post-Merge Deployment\n```bash\n#!/bin/bash\n# .dmux-hooks/post_merge\n\nset -e\ncd \"$DMUX_ROOT\"\n\n# Only deploy from main/master\nif [ \"$DMUX_TARGET_BRANCH\" != \"main\" ] && [ \"$DMUX_TARGET_BRANCH\" != \"master\" ]; then\n exit 0\nfi\n\n# Push to remote\ngit push origin \"$DMUX_TARGET_BRANCH\"\n\n# Trigger deployment (example: Vercel)\nif [ -n \"$VERCEL_TOKEN\" ]; then\n curl -s -X POST \"https://api.vercel.com/v1/deployments\" -H \"Authorization: Bearer $VERCEL_TOKEN\" -H \"Content-Type: application/json\" -d '{\"name\": \"my-project\"}' > /dev/null\nfi\n\n# Close GitHub issue if prompt contains #123\nISSUE=$(echo \"$DMUX_PROMPT\" | grep -oP '#Kd+' | head -1)\nif [ -n \"$ISSUE\" ] && command -v gh &> /dev/null; then\n gh issue close \"$ISSUE\" -c \"Resolved in $DMUX_SLUG, merged to $DMUX_TARGET_BRANCH\" 2>/dev/null || true\nfi\n```\n\n## Best Practices\n\n1. **Always start with shebang**: `#!/bin/bash`\n2. **Set error handling**: `set -e` (exit on error)\n3. **Make executable**: `chmod +x .dmux-hooks/hook_name`\n4. **Background long operations**: Append `&` to avoid blocking\n5. **Check for required tools**: `command -v tool &> /dev/null`\n6. **Log for debugging**: `echo \"[Hook] message\" >> \"$DMUX_ROOT/.dmux/hooks.log\"`\n7. **Handle missing vars gracefully**: `[ -z \"$VAR\" ] && exit 0`\n8. **Use silent curl**: `curl -s` to avoid noise in logs\n9. **Clean up temp files**: Remove files in `/tmp/`\n10. **Test before committing**: Run hooks manually with mock env vars\n\n## Testing Hooks\n\n### Manual Testing\n```bash\n# 1. Set environment variables\nexport DMUX_ROOT=\"$(pwd)\"\nexport DMUX_PANE_ID=\"test-pane\"\nexport DMUX_SLUG=\"test-branch\"\nexport DMUX_WORKTREE_PATH=\"$(pwd)\"\nexport DMUX_SERVER_PORT=\"3142\"\nexport DMUX_AGENT=\"claude\"\nexport DMUX_PROMPT=\"Test prompt\"\n\n# 2. Run hook directly\n./.dmux-hooks/worktree_created\n\n# 3. Check exit code\necho $? # Should be 0 for success\n```\n\n### Syntax Check\n```bash\n# Check for syntax errors without running\nbash -n ./.dmux-hooks/worktree_created\n```\n\n### Shellcheck (if available)\n```bash\nshellcheck ./.dmux-hooks/worktree_created\n```\n\n## Project Context Analysis\n\nBefore creating hooks, analyze these files in the project:\n\n### Package Manager Detection\n```bash\n# Check which package manager is used\nif [ -f \"pnpm-lock.yaml\" ]; then\n # Use: pnpm install, pnpm test, pnpm dev\nelif [ -f \"package-lock.json\" ]; then\n # Use: npm install, npm test, npm run dev\nelif [ -f \"yarn.lock\" ]; then\n # Use: yarn install, yarn test, yarn dev\nfi\n```\n\n### Test Command Discovery\n```bash\n# Read package.json to find test command\ncat package.json | grep '\"test\"'\n# Or with jq:\njq -r '.scripts.test' package.json\n```\n\n### Dev Command Discovery\n```bash\n# Read package.json to find dev command\ncat package.json | grep '\"dev\"'\n# Or with jq:\njq -r '.scripts.dev' package.json\n```\n\n### Environment Variables\n```bash\n# Check for .env files to copy\nls -la | grep '.env'\n```\n\n### Build System\n```bash\n# Detect build system\nif [ -f \"vite.config.ts\" ]; then\n # Vite project\nelif [ -f \"next.config.js\" ]; then\n # Next.js project\nelif [ -f \"nuxt.config.ts\" ]; then\n # Nuxt project\nfi\n```\n\n## Common Mistakes to Avoid\n\n\u274C **Blocking operations**: `sleep 60` (blocks dmux)\n\u2705 **Background long tasks**: `slow_operation &`\n\n\u274C **Hardcoded paths**: `/Users/me/project`\n\u2705 **Use variables**: `\"$DMUX_ROOT\"`\n\n\u274C **Assuming tools exist**: `pnpm install`\n\u2705 **Check first**: `command -v pnpm && pnpm install`\n\n\u274C **No error handling**: Script fails silently\n\u2705 **Set error mode**: `set -e` or check exit codes\n\n\u274C **Forgetting executable bit**: Hook won't run\n\u2705 **Make executable**: `chmod +x`\n\n\u274C **Noisy output**: Clutters dmux logs\n\u2705 **Silent operations**: `curl -s`, `> /dev/null 2>&1`\n\n\u274C **Not testing**: Deploy and hope\n\u2705 **Test manually**: Run with mock env vars first\n\n## Debugging\n\nIf a hook isn't working:\n\n1. **Check if file exists**: `ls -la .dmux-hooks/`\n2. **Check permissions**: Should show `x` in `rwxr-xr-x`\n3. **Check syntax**: `bash -n .dmux-hooks/hook_name`\n4. **Test manually**: Set env vars and run\n5. **Check logs**: dmux logs to stderr with `[Hooks]` prefix\n6. **Simplify**: Remove complex parts, test basic version\n7. **Check tool availability**: `command -v required_tool`\n\n### Debug Mode\n```bash\n#!/bin/bash\n# Add to top of hook for debugging\nset -x # Print each command before executing\nset -e # Exit on error\n\n# Your hook logic here\n```\n\n## Summary Checklist\n\nWhen creating a new hook:\n\n- [ ] Create file in `.dmux-hooks/`\n- [ ] Add shebang: `#!/bin/bash`\n- [ ] Make executable: `chmod +x`\n- [ ] Add `set -e` for error handling\n- [ ] Use environment variables (never hardcode paths)\n- [ ] Background long operations with `&`\n- [ ] Check for required tools before using\n- [ ] Test manually with mock env vars\n- [ ] Add comments explaining what it does\n- [ ] Commit to version control\n\n## Getting Help\n\n- **Full documentation**: See `HOOKS.md` in project root\n- **Claude-specific tips**: See `CLAUDE.md` in `.dmux-hooks/`\n- **Examples**: Check `.dmux-hooks/examples/` directory\n- **dmux API**: See `API.md` for REST endpoints\n\n---\n\n*This documentation was auto-generated from dmux source code.*\n*Version: 2025-10-13*\n";
|
|
13
|
+
/**
|
|
14
|
+
* README for the .dmux-hooks/ directory
|
|
15
|
+
*/
|
|
16
|
+
export declare const HOOKS_README = "# dmux Hooks\n\nThis directory contains hooks that run automatically at key lifecycle events in dmux.\n\n## Quick Start\n\n1. **Read the documentation**:\n - `AGENTS.md` - Complete reference (for any AI agent)\n - `CLAUDE.md` - Same content (Claude Code looks for this filename)\n\n2. **Check examples**:\n - `examples/` directory contains starter templates\n\n3. **Create a hook**:\n ```bash\n touch worktree_created\n chmod +x worktree_created\n nano worktree_created\n ```\n\n4. **Test it**:\n ```bash\n export DMUX_ROOT=\"$(pwd)\"\n export DMUX_WORKTREE_PATH=\"$(pwd)\"\n ./worktree_created\n ```\n\n## Available Hooks\n\n- `before_pane_create` - Before pane creation\n- `pane_created` - After pane created\n- `worktree_created` - After worktree setup\n- `before_pane_close` - Before closing\n- `pane_closed` - After closed\n- `before_worktree_remove` - Before worktree removal\n- `worktree_removed` - After worktree removed\n- `pre_merge` - Before merge\n- `post_merge` - After merge\n- `run_test` - When running tests\n- `run_dev` - When starting dev server\n\n## Documentation\n\nSee `AGENTS.md` or `CLAUDE.md` for complete documentation including:\n- Environment variables\n- HTTP callback API\n- Common patterns\n- Best practices\n- Testing strategies\n\n## Note\n\nThis directory is **version controlled**. Hooks you create here will be shared with your team.\n";
|
|
17
|
+
/**
|
|
18
|
+
* Example: worktree_created hook
|
|
19
|
+
*/
|
|
20
|
+
export declare const EXAMPLE_WORKTREE_CREATED = "#!/bin/bash\n# Example: worktree_created hook\n#\n# This hook runs after a new worktree is created and the agent is launched.\n# Use it to set up the worktree environment (install deps, copy configs, etc.)\n\nset -e # Exit on error\n\necho \"[Hook] Setting up worktree: $DMUX_SLUG\"\n\ncd \"$DMUX_WORKTREE_PATH\"\n\n# Install dependencies in background (don't block dmux)\nif [ -f \"pnpm-lock.yaml\" ]; then\n echo \"[Hook] Installing dependencies with pnpm...\"\n pnpm install --prefer-offline &\nelif [ -f \"package-lock.json\" ]; then\n echo \"[Hook] Installing dependencies with npm...\"\n npm install &\nelif [ -f \"yarn.lock\" ]; then\n echo \"[Hook] Installing dependencies with yarn...\"\n yarn install &\nfi\n\n# Copy environment file if it exists\nif [ -f \"$DMUX_ROOT/.env.local\" ]; then\n echo \"[Hook] Copying .env.local\"\n cp \"$DMUX_ROOT/.env.local\" \"$DMUX_WORKTREE_PATH/.env.local\"\nfi\n\n# Set custom git config for this worktree\necho \"[Hook] Configuring git\"\ngit config user.name \"dmux-agent/$DMUX_SLUG\"\ngit config user.email \"agent@dmux.local\"\n\n# Create a log entry\necho \"[$(date)] Created worktree: $DMUX_SLUG | Agent: $DMUX_AGENT | Prompt: $DMUX_PROMPT\" \\\n >> \"$DMUX_ROOT/.dmux/worktree_history.log\"\n\necho \"[Hook] Worktree setup complete!\"\n";
|
|
21
|
+
/**
|
|
22
|
+
* Example: run_dev hook
|
|
23
|
+
*/
|
|
24
|
+
export declare const EXAMPLE_RUN_DEV = "#!/bin/bash\n# Example: run_dev hook\n#\n# This hook starts a dev server and optionally creates a tunnel for sharing.\n# It reports the server URL back to dmux via the HTTP API.\n\nset -e\n\necho \"[Hook] Starting dev server for $DMUX_SLUG\"\n\ncd \"$DMUX_WORKTREE_PATH\"\nAPI_URL=\"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev\"\n\n# Update status: starting\ncurl -s -X PUT \"$API_URL\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"status\": \"running\"}' > /dev/null\n\n# Start dev server in background\n# Adjust the command for your project (pnpm dev, npm run dev, vite, etc.)\nLOG_FILE=\"/tmp/dmux-dev-$DMUX_PANE_ID.log\"\npnpm dev > \"$LOG_FILE\" 2>&1 &\nDEV_PID=$!\n\n# Wait for server to be ready\necho \"[Hook] Waiting for dev server to start...\"\nsleep 5\n\n# Detect port from log output\n# Adjust the grep pattern for your dev server's output format\nPORT=$(grep -oP '(?<=localhost:)\\d+' \"$LOG_FILE\" | head -1)\n\nif [ -z \"$PORT\" ]; then\n echo \"[Hook] Warning: Could not detect port from logs, using default 3000\"\n PORT=3000\nfi\n\nLOCAL_URL=\"http://localhost:$PORT\"\necho \"[Hook] Dev server running at $LOCAL_URL\"\n\n# Optional: Create a public tunnel (uncomment to enable)\n# Requires ngrok, cloudflared, or another tunneling tool\n\n# Example with cloudflared:\n# TUNNEL_URL=$(cloudflared tunnel --url \"$LOCAL_URL\" 2>&1 | \\\n# grep -oP 'https://[a-z0-9-]+\\.trycloudflare\\.com' | head -1)\n\n# Example with ngrok:\n# TUNNEL_URL=$(ngrok http $PORT --log=stdout 2>&1 | \\\n# grep -oP 'url=https://[^\"]+' | head -1 | cut -d= -f2)\n\n# For now, just use local URL (uncomment tunnel code above to enable)\nFINAL_URL=\"$LOCAL_URL\"\n\n# Report status back to dmux\ncurl -s -X PUT \"$API_URL\" \\\n -H \"Content-Type: application/json\" \\\n -d \"{\\\"status\\\": \\\"running\\\", \\\"url\\\": \\\"$FINAL_URL\\\"}\" > /dev/null\n\necho \"[Hook] Dev server ready at: $FINAL_URL\"\necho \"[Hook] Dev server PID: $DEV_PID\"\necho \"[Hook] Log file: $LOG_FILE\"\n";
|
|
25
|
+
/**
|
|
26
|
+
* Example: run_test hook
|
|
27
|
+
*/
|
|
28
|
+
export declare const EXAMPLE_RUN_TEST = "#!/bin/bash\n# Example: run_test hook\n#\n# This hook runs tests and reports the status back to dmux via the HTTP API.\n# Status updates appear in real-time in the dmux UI.\n\nset -e\n\necho \"[Hook] Running tests for $DMUX_SLUG\"\n\ncd \"$DMUX_WORKTREE_PATH\"\nAPI_URL=\"http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test\"\n\n# Update status: running\ncurl -s -X PUT \"$API_URL\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"status\": \"running\"}' > /dev/null\n\necho \"[Hook] Running test suite...\"\n\n# Capture test output\nOUTPUT_FILE=\"/tmp/dmux-test-$DMUX_PANE_ID.txt\"\n\n# Run tests (adjust command for your project)\n# Examples:\n# - pnpm test\n# - npm test\n# - vitest run\n# - jest\n# - pytest\n# - cargo test\nif pnpm test > \"$OUTPUT_FILE\" 2>&1; then\n STATUS=\"passed\"\n echo \"[Hook] Tests passed \u2713\"\nelse\n STATUS=\"failed\"\n echo \"[Hook] Tests failed \u2717\"\nfi\n\n# Get output (truncate if too long)\nOUTPUT=$(head -c 5000 \"$OUTPUT_FILE\")\n\n# Report results back to dmux\ncurl -s -X PUT \"$API_URL\" \\\n -H \"Content-Type: application/json\" \\\n -d \"$(jq -n \\\n --arg status \"$STATUS\" \\\n --arg output \"$OUTPUT\" \\\n '{status: $status, output: $output}')\" > /dev/null\n\n# Cleanup\nrm -f \"$OUTPUT_FILE\"\n\necho \"[Hook] Test results reported to dmux\"\n\n# Exit with test status\nif [ \"$STATUS\" = \"passed\" ]; then\n exit 0\nelse\n exit 1\nfi\n";
|
|
29
|
+
/**
|
|
30
|
+
* Example: post_merge hook
|
|
31
|
+
*/
|
|
32
|
+
export declare const EXAMPLE_POST_MERGE = "#!/bin/bash\n# Example: post_merge hook\n#\n# This hook runs after a successful merge into the target branch.\n# Use it to trigger deployments, close issues, notify teams, etc.\n\nset -e\n\necho \"[Hook] Post-merge processing for $DMUX_SLUG \u2192 $DMUX_TARGET_BRANCH\"\n\ncd \"$DMUX_ROOT\"\n\n# Push to remote if merging to main/master\nif [ \"$DMUX_TARGET_BRANCH\" = \"main\" ] || [ \"$DMUX_TARGET_BRANCH\" = \"master\" ]; then\n echo \"[Hook] Pushing to origin/$DMUX_TARGET_BRANCH\"\n git push origin \"$DMUX_TARGET_BRANCH\"\n\n # Optional: Trigger deployment\n # if [ -n \"$VERCEL_TOKEN\" ]; then\n # echo \"[Hook] Triggering Vercel deployment...\"\n # curl -X POST \"https://api.vercel.com/v1/deployments\" \\\n # -H \"Authorization: Bearer $VERCEL_TOKEN\" \\\n # -H \"Content-Type: application/json\" \\\n # -d '{\n # \"name\": \"my-project\",\n # \"gitSource\": {\n # \"type\": \"github\",\n # \"ref\": \"main\"\n # }\n # }'\n # fi\nfi\n\n# Close related GitHub issue (if prompt contains #123 format)\nISSUE_NUM=$(echo \"$DMUX_PROMPT\" | grep -oP '#\\K\\d+' | head -1)\nif [ -n \"$ISSUE_NUM\" ]; then\n echo \"[Hook] Closing GitHub issue #$ISSUE_NUM\"\n if command -v gh &> /dev/null; then\n gh issue close \"$ISSUE_NUM\" \\\n -c \"Resolved in branch $DMUX_SLUG, merged to $DMUX_TARGET_BRANCH\" \\\n 2>/dev/null || echo \"[Hook] Warning: Failed to close issue (maybe already closed?)\"\n else\n echo \"[Hook] GitHub CLI (gh) not found, skipping issue close\"\n fi\nfi\n\n# Send notification to Slack\n# if [ -n \"$SLACK_WEBHOOK\" ]; then\n# echo \"[Hook] Sending Slack notification\"\n# curl -s -X POST \"$SLACK_WEBHOOK\" \\\n# -H \"Content-Type: application/json\" \\\n# -d \"{\n# \\\"text\\\": \\\"Merged: $DMUX_SLUG \u2192 $DMUX_TARGET_BRANCH\\\",\n# \\\"blocks\\\": [\n# {\n# \\\"type\\\": \\\"section\\\",\n# \\\"text\\\": {\n# \\\"type\\\": \\\"mrkdwn\\\",\n# \\\"text\\\": \\\"*Branch Merged* :rocket:\\n\\n*From:* \\`$DMUX_SLUG\\`\\n*To:* \\`$DMUX_TARGET_BRANCH\\`\\n*Task:* $DMUX_PROMPT\\\"\n# }\n# }\n# ]\n# }\" > /dev/null\n# fi\n\necho \"[Hook] Post-merge processing complete\"\n";
|
|
33
|
+
/**
|
|
34
|
+
* All embedded examples for easy iteration
|
|
35
|
+
*/
|
|
36
|
+
export declare const EXAMPLE_HOOKS: {
|
|
37
|
+
'worktree_created.example': string;
|
|
38
|
+
'run_dev.example': string;
|
|
39
|
+
'run_test.example': string;
|
|
40
|
+
'post_merge.example': string;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=hooksDocs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooksDocs.d.ts","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,svYAAY,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,YAAY,03CAqDxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,wxCAwCpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,2+DA8D3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,86CA6D5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,yvEAkE9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;CAKzB,CAAC"}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded Hooks Documentation
|
|
3
|
+
*
|
|
4
|
+
* This file contains all documentation that gets written to .dmux-hooks/
|
|
5
|
+
* when the directory is initialized. The AGENTS_MD content is auto-generated
|
|
6
|
+
* and imported from generated-agents-doc.ts
|
|
7
|
+
*/
|
|
8
|
+
import { AGENTS_MD } from './generated-agents-doc.js';
|
|
9
|
+
/**
|
|
10
|
+
* Main documentation - gets written as both AGENTS.md and CLAUDE.md
|
|
11
|
+
* Different agents look for different filenames, but content is identical
|
|
12
|
+
*/
|
|
13
|
+
export const HOOKS_DOCUMENTATION = AGENTS_MD;
|
|
14
|
+
/**
|
|
15
|
+
* README for the .dmux-hooks/ directory
|
|
16
|
+
*/
|
|
17
|
+
export const HOOKS_README = `# dmux Hooks
|
|
18
|
+
|
|
19
|
+
This directory contains hooks that run automatically at key lifecycle events in dmux.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
1. **Read the documentation**:
|
|
24
|
+
- \`AGENTS.md\` - Complete reference (for any AI agent)
|
|
25
|
+
- \`CLAUDE.md\` - Same content (Claude Code looks for this filename)
|
|
26
|
+
|
|
27
|
+
2. **Check examples**:
|
|
28
|
+
- \`examples/\` directory contains starter templates
|
|
29
|
+
|
|
30
|
+
3. **Create a hook**:
|
|
31
|
+
\`\`\`bash
|
|
32
|
+
touch worktree_created
|
|
33
|
+
chmod +x worktree_created
|
|
34
|
+
nano worktree_created
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
4. **Test it**:
|
|
38
|
+
\`\`\`bash
|
|
39
|
+
export DMUX_ROOT="\$(pwd)"
|
|
40
|
+
export DMUX_WORKTREE_PATH="\$(pwd)"
|
|
41
|
+
./worktree_created
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
## Available Hooks
|
|
45
|
+
|
|
46
|
+
- \`before_pane_create\` - Before pane creation
|
|
47
|
+
- \`pane_created\` - After pane created
|
|
48
|
+
- \`worktree_created\` - After worktree setup
|
|
49
|
+
- \`before_pane_close\` - Before closing
|
|
50
|
+
- \`pane_closed\` - After closed
|
|
51
|
+
- \`before_worktree_remove\` - Before worktree removal
|
|
52
|
+
- \`worktree_removed\` - After worktree removed
|
|
53
|
+
- \`pre_merge\` - Before merge
|
|
54
|
+
- \`post_merge\` - After merge
|
|
55
|
+
- \`run_test\` - When running tests
|
|
56
|
+
- \`run_dev\` - When starting dev server
|
|
57
|
+
|
|
58
|
+
## Documentation
|
|
59
|
+
|
|
60
|
+
See \`AGENTS.md\` or \`CLAUDE.md\` for complete documentation including:
|
|
61
|
+
- Environment variables
|
|
62
|
+
- HTTP callback API
|
|
63
|
+
- Common patterns
|
|
64
|
+
- Best practices
|
|
65
|
+
- Testing strategies
|
|
66
|
+
|
|
67
|
+
## Note
|
|
68
|
+
|
|
69
|
+
This directory is **version controlled**. Hooks you create here will be shared with your team.
|
|
70
|
+
`;
|
|
71
|
+
/**
|
|
72
|
+
* Example: worktree_created hook
|
|
73
|
+
*/
|
|
74
|
+
export const EXAMPLE_WORKTREE_CREATED = `#!/bin/bash
|
|
75
|
+
# Example: worktree_created hook
|
|
76
|
+
#
|
|
77
|
+
# This hook runs after a new worktree is created and the agent is launched.
|
|
78
|
+
# Use it to set up the worktree environment (install deps, copy configs, etc.)
|
|
79
|
+
|
|
80
|
+
set -e # Exit on error
|
|
81
|
+
|
|
82
|
+
echo "[Hook] Setting up worktree: $DMUX_SLUG"
|
|
83
|
+
|
|
84
|
+
cd "$DMUX_WORKTREE_PATH"
|
|
85
|
+
|
|
86
|
+
# Install dependencies in background (don't block dmux)
|
|
87
|
+
if [ -f "pnpm-lock.yaml" ]; then
|
|
88
|
+
echo "[Hook] Installing dependencies with pnpm..."
|
|
89
|
+
pnpm install --prefer-offline &
|
|
90
|
+
elif [ -f "package-lock.json" ]; then
|
|
91
|
+
echo "[Hook] Installing dependencies with npm..."
|
|
92
|
+
npm install &
|
|
93
|
+
elif [ -f "yarn.lock" ]; then
|
|
94
|
+
echo "[Hook] Installing dependencies with yarn..."
|
|
95
|
+
yarn install &
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Copy environment file if it exists
|
|
99
|
+
if [ -f "$DMUX_ROOT/.env.local" ]; then
|
|
100
|
+
echo "[Hook] Copying .env.local"
|
|
101
|
+
cp "$DMUX_ROOT/.env.local" "$DMUX_WORKTREE_PATH/.env.local"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Set custom git config for this worktree
|
|
105
|
+
echo "[Hook] Configuring git"
|
|
106
|
+
git config user.name "dmux-agent/$DMUX_SLUG"
|
|
107
|
+
git config user.email "agent@dmux.local"
|
|
108
|
+
|
|
109
|
+
# Create a log entry
|
|
110
|
+
echo "[\$(date)] Created worktree: $DMUX_SLUG | Agent: $DMUX_AGENT | Prompt: $DMUX_PROMPT" \\
|
|
111
|
+
>> "$DMUX_ROOT/.dmux/worktree_history.log"
|
|
112
|
+
|
|
113
|
+
echo "[Hook] Worktree setup complete!"
|
|
114
|
+
`;
|
|
115
|
+
/**
|
|
116
|
+
* Example: run_dev hook
|
|
117
|
+
*/
|
|
118
|
+
export const EXAMPLE_RUN_DEV = `#!/bin/bash
|
|
119
|
+
# Example: run_dev hook
|
|
120
|
+
#
|
|
121
|
+
# This hook starts a dev server and optionally creates a tunnel for sharing.
|
|
122
|
+
# It reports the server URL back to dmux via the HTTP API.
|
|
123
|
+
|
|
124
|
+
set -e
|
|
125
|
+
|
|
126
|
+
echo "[Hook] Starting dev server for $DMUX_SLUG"
|
|
127
|
+
|
|
128
|
+
cd "$DMUX_WORKTREE_PATH"
|
|
129
|
+
API_URL="http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/dev"
|
|
130
|
+
|
|
131
|
+
# Update status: starting
|
|
132
|
+
curl -s -X PUT "$API_URL" \\
|
|
133
|
+
-H "Content-Type: application/json" \\
|
|
134
|
+
-d '{"status": "running"}' > /dev/null
|
|
135
|
+
|
|
136
|
+
# Start dev server in background
|
|
137
|
+
# Adjust the command for your project (pnpm dev, npm run dev, vite, etc.)
|
|
138
|
+
LOG_FILE="/tmp/dmux-dev-$DMUX_PANE_ID.log"
|
|
139
|
+
pnpm dev > "$LOG_FILE" 2>&1 &
|
|
140
|
+
DEV_PID=$!
|
|
141
|
+
|
|
142
|
+
# Wait for server to be ready
|
|
143
|
+
echo "[Hook] Waiting for dev server to start..."
|
|
144
|
+
sleep 5
|
|
145
|
+
|
|
146
|
+
# Detect port from log output
|
|
147
|
+
# Adjust the grep pattern for your dev server's output format
|
|
148
|
+
PORT=\$(grep -oP '(?<=localhost:)\\d+' "$LOG_FILE" | head -1)
|
|
149
|
+
|
|
150
|
+
if [ -z "$PORT" ]; then
|
|
151
|
+
echo "[Hook] Warning: Could not detect port from logs, using default 3000"
|
|
152
|
+
PORT=3000
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
LOCAL_URL="http://localhost:$PORT"
|
|
156
|
+
echo "[Hook] Dev server running at $LOCAL_URL"
|
|
157
|
+
|
|
158
|
+
# Optional: Create a public tunnel (uncomment to enable)
|
|
159
|
+
# Requires ngrok, cloudflared, or another tunneling tool
|
|
160
|
+
|
|
161
|
+
# Example with cloudflared:
|
|
162
|
+
# TUNNEL_URL=\$(cloudflared tunnel --url "$LOCAL_URL" 2>&1 | \\
|
|
163
|
+
# grep -oP 'https://[a-z0-9-]+\\.trycloudflare\\.com' | head -1)
|
|
164
|
+
|
|
165
|
+
# Example with ngrok:
|
|
166
|
+
# TUNNEL_URL=\$(ngrok http $PORT --log=stdout 2>&1 | \\
|
|
167
|
+
# grep -oP 'url=https://[^"]+' | head -1 | cut -d= -f2)
|
|
168
|
+
|
|
169
|
+
# For now, just use local URL (uncomment tunnel code above to enable)
|
|
170
|
+
FINAL_URL="$LOCAL_URL"
|
|
171
|
+
|
|
172
|
+
# Report status back to dmux
|
|
173
|
+
curl -s -X PUT "$API_URL" \\
|
|
174
|
+
-H "Content-Type: application/json" \\
|
|
175
|
+
-d "{\\"status\\": \\"running\\", \\"url\\": \\"$FINAL_URL\\"}" > /dev/null
|
|
176
|
+
|
|
177
|
+
echo "[Hook] Dev server ready at: $FINAL_URL"
|
|
178
|
+
echo "[Hook] Dev server PID: $DEV_PID"
|
|
179
|
+
echo "[Hook] Log file: $LOG_FILE"
|
|
180
|
+
`;
|
|
181
|
+
/**
|
|
182
|
+
* Example: run_test hook
|
|
183
|
+
*/
|
|
184
|
+
export const EXAMPLE_RUN_TEST = `#!/bin/bash
|
|
185
|
+
# Example: run_test hook
|
|
186
|
+
#
|
|
187
|
+
# This hook runs tests and reports the status back to dmux via the HTTP API.
|
|
188
|
+
# Status updates appear in real-time in the dmux UI.
|
|
189
|
+
|
|
190
|
+
set -e
|
|
191
|
+
|
|
192
|
+
echo "[Hook] Running tests for $DMUX_SLUG"
|
|
193
|
+
|
|
194
|
+
cd "$DMUX_WORKTREE_PATH"
|
|
195
|
+
API_URL="http://localhost:$DMUX_SERVER_PORT/api/panes/$DMUX_PANE_ID/test"
|
|
196
|
+
|
|
197
|
+
# Update status: running
|
|
198
|
+
curl -s -X PUT "$API_URL" \\
|
|
199
|
+
-H "Content-Type: application/json" \\
|
|
200
|
+
-d '{"status": "running"}' > /dev/null
|
|
201
|
+
|
|
202
|
+
echo "[Hook] Running test suite..."
|
|
203
|
+
|
|
204
|
+
# Capture test output
|
|
205
|
+
OUTPUT_FILE="/tmp/dmux-test-$DMUX_PANE_ID.txt"
|
|
206
|
+
|
|
207
|
+
# Run tests (adjust command for your project)
|
|
208
|
+
# Examples:
|
|
209
|
+
# - pnpm test
|
|
210
|
+
# - npm test
|
|
211
|
+
# - vitest run
|
|
212
|
+
# - jest
|
|
213
|
+
# - pytest
|
|
214
|
+
# - cargo test
|
|
215
|
+
if pnpm test > "$OUTPUT_FILE" 2>&1; then
|
|
216
|
+
STATUS="passed"
|
|
217
|
+
echo "[Hook] Tests passed ✓"
|
|
218
|
+
else
|
|
219
|
+
STATUS="failed"
|
|
220
|
+
echo "[Hook] Tests failed ✗"
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
# Get output (truncate if too long)
|
|
224
|
+
OUTPUT=\$(head -c 5000 "$OUTPUT_FILE")
|
|
225
|
+
|
|
226
|
+
# Report results back to dmux
|
|
227
|
+
curl -s -X PUT "$API_URL" \\
|
|
228
|
+
-H "Content-Type: application/json" \\
|
|
229
|
+
-d "\$(jq -n \\
|
|
230
|
+
--arg status "$STATUS" \\
|
|
231
|
+
--arg output "$OUTPUT" \\
|
|
232
|
+
'{status: \$status, output: \$output}')" > /dev/null
|
|
233
|
+
|
|
234
|
+
# Cleanup
|
|
235
|
+
rm -f "$OUTPUT_FILE"
|
|
236
|
+
|
|
237
|
+
echo "[Hook] Test results reported to dmux"
|
|
238
|
+
|
|
239
|
+
# Exit with test status
|
|
240
|
+
if [ "$STATUS" = "passed" ]; then
|
|
241
|
+
exit 0
|
|
242
|
+
else
|
|
243
|
+
exit 1
|
|
244
|
+
fi
|
|
245
|
+
`;
|
|
246
|
+
/**
|
|
247
|
+
* Example: post_merge hook
|
|
248
|
+
*/
|
|
249
|
+
export const EXAMPLE_POST_MERGE = `#!/bin/bash
|
|
250
|
+
# Example: post_merge hook
|
|
251
|
+
#
|
|
252
|
+
# This hook runs after a successful merge into the target branch.
|
|
253
|
+
# Use it to trigger deployments, close issues, notify teams, etc.
|
|
254
|
+
|
|
255
|
+
set -e
|
|
256
|
+
|
|
257
|
+
echo "[Hook] Post-merge processing for $DMUX_SLUG → $DMUX_TARGET_BRANCH"
|
|
258
|
+
|
|
259
|
+
cd "$DMUX_ROOT"
|
|
260
|
+
|
|
261
|
+
# Push to remote if merging to main/master
|
|
262
|
+
if [ "$DMUX_TARGET_BRANCH" = "main" ] || [ "$DMUX_TARGET_BRANCH" = "master" ]; then
|
|
263
|
+
echo "[Hook] Pushing to origin/$DMUX_TARGET_BRANCH"
|
|
264
|
+
git push origin "$DMUX_TARGET_BRANCH"
|
|
265
|
+
|
|
266
|
+
# Optional: Trigger deployment
|
|
267
|
+
# if [ -n "$VERCEL_TOKEN" ]; then
|
|
268
|
+
# echo "[Hook] Triggering Vercel deployment..."
|
|
269
|
+
# curl -X POST "https://api.vercel.com/v1/deployments" \\
|
|
270
|
+
# -H "Authorization: Bearer $VERCEL_TOKEN" \\
|
|
271
|
+
# -H "Content-Type: application/json" \\
|
|
272
|
+
# -d '{
|
|
273
|
+
# "name": "my-project",
|
|
274
|
+
# "gitSource": {
|
|
275
|
+
# "type": "github",
|
|
276
|
+
# "ref": "main"
|
|
277
|
+
# }
|
|
278
|
+
# }'
|
|
279
|
+
# fi
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
# Close related GitHub issue (if prompt contains #123 format)
|
|
283
|
+
ISSUE_NUM=\$(echo "$DMUX_PROMPT" | grep -oP '#\\K\\d+' | head -1)
|
|
284
|
+
if [ -n "$ISSUE_NUM" ]; then
|
|
285
|
+
echo "[Hook] Closing GitHub issue #$ISSUE_NUM"
|
|
286
|
+
if command -v gh &> /dev/null; then
|
|
287
|
+
gh issue close "$ISSUE_NUM" \\
|
|
288
|
+
-c "Resolved in branch $DMUX_SLUG, merged to $DMUX_TARGET_BRANCH" \\
|
|
289
|
+
2>/dev/null || echo "[Hook] Warning: Failed to close issue (maybe already closed?)"
|
|
290
|
+
else
|
|
291
|
+
echo "[Hook] GitHub CLI (gh) not found, skipping issue close"
|
|
292
|
+
fi
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
# Send notification to Slack
|
|
296
|
+
# if [ -n "$SLACK_WEBHOOK" ]; then
|
|
297
|
+
# echo "[Hook] Sending Slack notification"
|
|
298
|
+
# curl -s -X POST "$SLACK_WEBHOOK" \\
|
|
299
|
+
# -H "Content-Type: application/json" \\
|
|
300
|
+
# -d "{
|
|
301
|
+
# \\"text\\": \\"Merged: $DMUX_SLUG → $DMUX_TARGET_BRANCH\\",
|
|
302
|
+
# \\"blocks\\": [
|
|
303
|
+
# {
|
|
304
|
+
# \\"type\\": \\"section\\",
|
|
305
|
+
# \\"text\\": {
|
|
306
|
+
# \\"type\\": \\"mrkdwn\\",
|
|
307
|
+
# \\"text\\": \\"*Branch Merged* :rocket:\\n\\n*From:* \\\`$DMUX_SLUG\\\`\\n*To:* \\\`$DMUX_TARGET_BRANCH\\\`\\n*Task:* $DMUX_PROMPT\\"
|
|
308
|
+
# }
|
|
309
|
+
# }
|
|
310
|
+
# ]
|
|
311
|
+
# }" > /dev/null
|
|
312
|
+
# fi
|
|
313
|
+
|
|
314
|
+
echo "[Hook] Post-merge processing complete"
|
|
315
|
+
`;
|
|
316
|
+
/**
|
|
317
|
+
* All embedded examples for easy iteration
|
|
318
|
+
*/
|
|
319
|
+
export const EXAMPLE_HOOKS = {
|
|
320
|
+
'worktree_created.example': EXAMPLE_WORKTREE_CREATED,
|
|
321
|
+
'run_dev.example': EXAMPLE_RUN_DEV,
|
|
322
|
+
'run_test.example': EXAMPLE_RUN_TEST,
|
|
323
|
+
'post_merge.example': EXAMPLE_POST_MERGE,
|
|
324
|
+
};
|
|
325
|
+
//# sourceMappingURL=hooksDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooksDocs.js","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqD3B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCvC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8D9B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D/B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkEjC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,0BAA0B,EAAE,wBAAwB;IACpD,iBAAiB,EAAE,eAAe;IAClC,kBAAkB,EAAE,gBAAgB;IACpC,oBAAoB,EAAE,kBAAkB;CACzC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Captures the last N lines from a tmux pane, automatically skipping trailing blank lines.
|
|
3
|
+
* If the captured content ends with blank lines, it will fetch more lines to ensure
|
|
4
|
+
* we get actual content.
|
|
5
|
+
*
|
|
6
|
+
* @param paneId - The tmux pane ID to capture from
|
|
7
|
+
* @param lines - Number of non-blank lines to capture (default: 50)
|
|
8
|
+
* @param maxAttempts - Maximum number of fetch attempts to find content (default: 5)
|
|
9
|
+
* @returns The captured content with trailing blank lines removed, or empty string on failure
|
|
10
|
+
*/
|
|
11
|
+
export declare function capturePaneContent(paneId: string, lines?: number, maxAttempts?: number): string;
|
|
12
|
+
/**
|
|
13
|
+
* Captures the last N lines from a tmux pane without filtering blank lines.
|
|
14
|
+
* Use this when you specifically want raw output including blanks.
|
|
15
|
+
*
|
|
16
|
+
* @param paneId - The tmux pane ID to capture from
|
|
17
|
+
* @param lines - Number of lines to capture (default: 50)
|
|
18
|
+
* @returns The raw captured content, or empty string on failure
|
|
19
|
+
*/
|
|
20
|
+
export declare function capturePaneContentRaw(paneId: string, lines?: number): string;
|
|
21
|
+
//# sourceMappingURL=paneCapture.d.ts.map
|