dmux 5.2.0 → 5.3.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 +8 -4
- package/dist/DmuxApp.d.ts.map +1 -1
- package/dist/DmuxApp.js +99 -56
- package/dist/DmuxApp.js.map +1 -1
- package/dist/actions/implementations/closeAction.d.ts.map +1 -1
- package/dist/actions/implementations/closeAction.js +42 -13
- package/dist/actions/implementations/closeAction.js.map +1 -1
- package/dist/actions/implementations/index.d.ts +1 -0
- package/dist/actions/implementations/index.d.ts.map +1 -1
- package/dist/actions/implementations/index.js +3 -0
- package/dist/actions/implementations/index.js.map +1 -1
- package/dist/actions/implementations/mergeAction.d.ts.map +1 -1
- package/dist/actions/implementations/mergeAction.js +59 -19
- package/dist/actions/implementations/mergeAction.js.map +1 -1
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +6 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/merge/conflictResolution.d.ts.map +1 -1
- package/dist/actions/merge/conflictResolution.js +17 -12
- package/dist/actions/merge/conflictResolution.js.map +1 -1
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.d.ts.map +1 -1
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.js +8 -6
- package/dist/actions/merge/issueHandlers/mainDirtyHandler.js.map +1 -1
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.d.ts +1 -1
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.d.ts.map +1 -1
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.js +9 -2
- package/dist/actions/merge/issueHandlers/worktreeUncommittedHandler.js.map +1 -1
- package/dist/actions/merge/multiMergeOrchestrator.d.ts.map +1 -1
- package/dist/actions/merge/multiMergeOrchestrator.js +33 -14
- package/dist/actions/merge/multiMergeOrchestrator.js.map +1 -1
- package/dist/actions/types.d.ts +4 -2
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js +19 -1
- package/dist/actions/types.js.map +1 -1
- package/dist/components/dialogs/AgentChoiceDialog.d.ts +2 -1
- package/dist/components/dialogs/AgentChoiceDialog.d.ts.map +1 -1
- package/dist/components/dialogs/AgentChoiceDialog.js +4 -5
- package/dist/components/dialogs/AgentChoiceDialog.js.map +1 -1
- package/dist/components/panes/PaneCard.d.ts +1 -3
- package/dist/components/panes/PaneCard.d.ts.map +1 -1
- package/dist/components/panes/PaneCard.js +54 -37
- package/dist/components/panes/PaneCard.js.map +1 -1
- package/dist/components/panes/PanesGrid.d.ts +1 -0
- package/dist/components/panes/PanesGrid.d.ts.map +1 -1
- package/dist/components/panes/PanesGrid.js +60 -78
- package/dist/components/panes/PanesGrid.js.map +1 -1
- package/dist/components/popups/agentChoicePopup.d.ts +2 -2
- package/dist/components/popups/agentChoicePopup.js +85 -56
- package/dist/components/popups/agentChoicePopup.js.map +1 -1
- package/dist/components/popups/diffPeekPopup.d.ts +7 -0
- package/dist/components/popups/diffPeekPopup.d.ts.map +1 -0
- package/dist/components/popups/diffPeekPopup.js +99 -0
- package/dist/components/popups/diffPeekPopup.js.map +1 -0
- package/dist/components/popups/enabledAgentsPopup.d.ts +7 -0
- package/dist/components/popups/enabledAgentsPopup.d.ts.map +1 -0
- package/dist/components/popups/enabledAgentsPopup.js +196 -0
- package/dist/components/popups/enabledAgentsPopup.js.map +1 -0
- package/dist/components/popups/kebabMenuPopup.js +2 -2
- package/dist/components/popups/kebabMenuPopup.js.map +1 -1
- package/dist/components/popups/mergeUncommittedChoicePopup.d.ts +7 -0
- package/dist/components/popups/mergeUncommittedChoicePopup.d.ts.map +1 -0
- package/dist/components/popups/mergeUncommittedChoicePopup.js +289 -0
- package/dist/components/popups/mergeUncommittedChoicePopup.js.map +1 -0
- package/dist/components/popups/newPanePopup.js +8 -0
- package/dist/components/popups/newPanePopup.js.map +1 -1
- package/dist/components/popups/reopenWorktreePopup.js +33 -3
- package/dist/components/popups/reopenWorktreePopup.js.map +1 -1
- package/dist/components/popups/shortcutsPopup.js +15 -12
- package/dist/components/popups/shortcutsPopup.js.map +1 -1
- package/dist/components/popups/singleAgentChoicePopup.d.ts +7 -0
- package/dist/components/popups/singleAgentChoicePopup.d.ts.map +1 -0
- package/dist/components/popups/singleAgentChoicePopup.js +95 -0
- package/dist/components/popups/singleAgentChoicePopup.js.map +1 -0
- package/dist/components/ui/FooterHelp.js +1 -1
- package/dist/components/ui/FooterHelp.js.map +1 -1
- package/dist/hooks/useActionSystem.d.ts +1 -1
- package/dist/hooks/useActionSystem.d.ts.map +1 -1
- package/dist/hooks/useActionSystem.js +1 -1
- package/dist/hooks/useActionSystem.js.map +1 -1
- package/dist/hooks/useAgentDetection.d.ts +2 -2
- package/dist/hooks/useAgentDetection.d.ts.map +1 -1
- package/dist/hooks/useAgentDetection.js +18 -88
- package/dist/hooks/useAgentDetection.js.map +1 -1
- package/dist/hooks/useAutoUpdater.d.ts.map +1 -1
- package/dist/hooks/useAutoUpdater.js +2 -4
- package/dist/hooks/useAutoUpdater.js.map +1 -1
- package/dist/hooks/useInputHandling.d.ts +5 -0
- package/dist/hooks/useInputHandling.d.ts.map +1 -1
- package/dist/hooks/useInputHandling.js +88 -15
- package/dist/hooks/useInputHandling.js.map +1 -1
- package/dist/hooks/useNavigation.d.ts +1 -1
- package/dist/hooks/useNavigation.d.ts.map +1 -1
- package/dist/hooks/useNavigation.js +26 -4
- package/dist/hooks/useNavigation.js.map +1 -1
- package/dist/hooks/usePaneCreation.d.ts +5 -2
- package/dist/hooks/usePaneCreation.d.ts.map +1 -1
- package/dist/hooks/usePaneCreation.js +123 -23
- package/dist/hooks/usePaneCreation.js.map +1 -1
- package/dist/hooks/usePaneSync.d.ts +1 -1
- package/dist/hooks/usePaneSync.d.ts.map +1 -1
- package/dist/hooks/usePaneSync.js +14 -1
- package/dist/hooks/usePaneSync.js.map +1 -1
- package/dist/hooks/usePanes.js +1 -1
- package/dist/hooks/usePanes.js.map +1 -1
- package/dist/hooks/useServices.d.ts +1 -1
- package/dist/hooks/useServices.d.ts.map +1 -1
- package/dist/hooks/useServices.js +2 -2
- package/dist/hooks/useServices.js.map +1 -1
- package/dist/index.js +194 -18
- package/dist/index.js.map +1 -1
- package/dist/layout/SpacerManager.d.ts.map +1 -1
- package/dist/layout/SpacerManager.js +2 -1
- package/dist/layout/SpacerManager.js.map +1 -1
- package/dist/services/PaneEventService.d.ts.map +1 -1
- package/dist/services/PaneEventService.js +2 -5
- package/dist/services/PaneEventService.js.map +1 -1
- package/dist/services/PaneWorkerManager.d.ts.map +1 -1
- package/dist/services/PaneWorkerManager.js +2 -14
- package/dist/services/PaneWorkerManager.js.map +1 -1
- package/dist/services/PopupManager.d.ts +7 -2
- package/dist/services/PopupManager.d.ts.map +1 -1
- package/dist/services/PopupManager.js +125 -19
- package/dist/services/PopupManager.js.map +1 -1
- package/dist/services/TmuxService.d.ts +9 -0
- package/dist/services/TmuxService.d.ts.map +1 -1
- package/dist/services/TmuxService.js +18 -2
- package/dist/services/TmuxService.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/agentDetection.d.ts +15 -8
- package/dist/utils/agentDetection.d.ts.map +1 -1
- package/dist/utils/agentDetection.js +49 -73
- package/dist/utils/agentDetection.js.map +1 -1
- package/dist/utils/agentLaunch.d.ts +60 -2
- package/dist/utils/agentLaunch.d.ts.map +1 -1
- package/dist/utils/agentLaunch.js +490 -41
- package/dist/utils/agentLaunch.js.map +1 -1
- package/dist/utils/agentPromptDispatch.d.ts +33 -0
- package/dist/utils/agentPromptDispatch.d.ts.map +1 -0
- package/dist/utils/agentPromptDispatch.js +99 -0
- package/dist/utils/agentPromptDispatch.js.map +1 -0
- package/dist/utils/asciiArt.d.ts.map +1 -1
- package/dist/utils/asciiArt.js +6 -7
- package/dist/utils/asciiArt.js.map +1 -1
- package/dist/utils/attachAgent.d.ts +21 -0
- package/dist/utils/attachAgent.d.ts.map +1 -0
- package/dist/utils/attachAgent.js +128 -0
- package/dist/utils/attachAgent.js.map +1 -0
- package/dist/utils/conflictResolutionPane.d.ts +2 -1
- package/dist/utils/conflictResolutionPane.d.ts.map +1 -1
- package/dist/utils/conflictResolutionPane.js +48 -53
- package/dist/utils/conflictResolutionPane.js.map +1 -1
- package/dist/utils/devSource.d.ts +7 -0
- package/dist/utils/devSource.d.ts.map +1 -0
- package/dist/utils/devSource.js +19 -0
- package/dist/utils/devSource.js.map +1 -0
- package/dist/utils/devWatchCommand.d.ts +8 -0
- package/dist/utils/devWatchCommand.d.ts.map +1 -0
- package/dist/utils/devWatchCommand.js +14 -0
- package/dist/utils/devWatchCommand.js.map +1 -0
- package/dist/utils/geminiTrust.d.ts +8 -0
- package/dist/utils/geminiTrust.d.ts.map +1 -0
- package/dist/utils/geminiTrust.js +67 -0
- package/dist/utils/geminiTrust.js.map +1 -0
- package/dist/utils/generated-agents-doc.d.ts +1 -1
- package/dist/utils/generated-agents-doc.js +3 -3
- package/dist/utils/hooksDocs.d.ts +2 -9
- package/dist/utils/hooksDocs.d.ts.map +1 -1
- package/dist/utils/hooksDocs.js +26 -6
- package/dist/utils/hooksDocs.js.map +1 -1
- package/dist/utils/paneCreation.d.ts +8 -2
- package/dist/utils/paneCreation.d.ts.map +1 -1
- package/dist/utils/paneCreation.js +82 -105
- package/dist/utils/paneCreation.js.map +1 -1
- package/dist/utils/paneGrouping.d.ts.map +1 -1
- package/dist/utils/paneGrouping.js +30 -0
- package/dist/utils/paneGrouping.js.map +1 -1
- package/dist/utils/projectActions.d.ts +5 -0
- package/dist/utils/projectActions.d.ts.map +1 -1
- package/dist/utils/projectActions.js +15 -4
- package/dist/utils/projectActions.js.map +1 -1
- package/dist/utils/reopenWorktree.d.ts +1 -1
- package/dist/utils/reopenWorktree.d.ts.map +1 -1
- package/dist/utils/reopenWorktree.js +23 -31
- package/dist/utils/reopenWorktree.js.map +1 -1
- package/dist/utils/runtimePaths.d.ts +2 -0
- package/dist/utils/runtimePaths.d.ts.map +1 -0
- package/dist/utils/runtimePaths.js +8 -0
- package/dist/utils/runtimePaths.js.map +1 -0
- package/dist/utils/settingsManager.d.ts.map +1 -1
- package/dist/utils/settingsManager.js +38 -5
- package/dist/utils/settingsManager.js.map +1 -1
- package/dist/utils/systemCheck.d.ts.map +1 -1
- package/dist/utils/systemCheck.js +0 -13
- package/dist/utils/systemCheck.js.map +1 -1
- package/dist/utils/welcomePane.d.ts +2 -1
- package/dist/utils/welcomePane.d.ts.map +1 -1
- package/dist/utils/welcomePane.js +3 -2
- package/dist/utils/welcomePane.js.map +1 -1
- package/dist/utils/welcomePaneManager.js +1 -1
- package/dist/utils/welcomePaneManager.js.map +1 -1
- package/dist/workers/PaneWorker.js.map +1 -1
- package/dist/workers/WorkerMessages.d.ts +2 -1
- package/dist/workers/WorkerMessages.d.ts.map +1 -1
- package/dist/workers/WorkerMessages.js.map +1 -1
- package/package.json +11 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { atomicWriteJsonSync } from './atomicWrite.js';
|
|
4
|
+
const TRUSTED_LEVEL = 'TRUST_FOLDER';
|
|
5
|
+
const DEFAULT_GEMINI_DIR = '.gemini';
|
|
6
|
+
const TRUSTED_FOLDERS_FILENAME = 'trustedFolders.json';
|
|
7
|
+
function getTrustedFoldersPath() {
|
|
8
|
+
const overridePath = process.env.GEMINI_CLI_TRUSTED_FOLDERS_PATH;
|
|
9
|
+
if (overridePath && overridePath.trim().length > 0) {
|
|
10
|
+
return overridePath;
|
|
11
|
+
}
|
|
12
|
+
const home = process.env.HOME || '';
|
|
13
|
+
if (!home) {
|
|
14
|
+
return '';
|
|
15
|
+
}
|
|
16
|
+
return path.join(home, DEFAULT_GEMINI_DIR, TRUSTED_FOLDERS_FILENAME);
|
|
17
|
+
}
|
|
18
|
+
function readTrustedFoldersConfig(filePath) {
|
|
19
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
24
|
+
const parsed = JSON.parse(raw);
|
|
25
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
26
|
+
const trustedFolders = {};
|
|
27
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
trustedFolders[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return trustedFolders;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Fall through to empty config on parse/read errors.
|
|
37
|
+
}
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Ensure Gemini treats the given workspace path as trusted.
|
|
42
|
+
*
|
|
43
|
+
* Gemini blocks interactive startup prompts in untrusted folders, which
|
|
44
|
+
* prevents dmux initial prompt bootstrap from running in fresh worktrees.
|
|
45
|
+
*/
|
|
46
|
+
export function ensureGeminiFolderTrusted(workspacePath) {
|
|
47
|
+
const trustedFoldersPath = getTrustedFoldersPath();
|
|
48
|
+
if (!trustedFoldersPath || !workspacePath) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const resolvedWorkspacePath = path.resolve(workspacePath);
|
|
52
|
+
const trustedFolders = readTrustedFoldersConfig(trustedFoldersPath);
|
|
53
|
+
if (trustedFolders[resolvedWorkspacePath] === TRUSTED_LEVEL) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
trustedFolders[resolvedWorkspacePath] = TRUSTED_LEVEL;
|
|
57
|
+
const trustedFoldersDir = path.dirname(trustedFoldersPath);
|
|
58
|
+
fs.mkdirSync(trustedFoldersDir, { recursive: true });
|
|
59
|
+
atomicWriteJsonSync(trustedFoldersPath, trustedFolders, true);
|
|
60
|
+
try {
|
|
61
|
+
fs.chmodSync(trustedFoldersPath, 0o600);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Ignore chmod failures on environments that do not support POSIX permissions.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=geminiTrust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geminiTrust.js","sourceRoot":"","sources":["../../src/utils/geminiTrust.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,aAAa,GAAG,cAAc,CAAC;AACrC,MAAM,kBAAkB,GAAG,SAAS,CAAC;AACrC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAIvD,SAAS,qBAAqB;IAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC;IACjE,IAAI,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,wBAAwB,CAAC,QAAgB;IAChD,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,MAAM,cAAc,GAAyB,EAAE,CAAC;YAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC9B,cAAc,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBAC9B,CAAC;YACH,CAAC;YACD,OAAO,cAAc,CAAC;QACxB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;IACvD,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,aAAqB;IAC7D,MAAM,kBAAkB,GAAG,qBAAqB,EAAE,CAAC;IACnD,IAAI,CAAC,kBAAkB,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,cAAc,GAAG,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;IAEpE,IAAI,cAAc,CAAC,qBAAqB,CAAC,KAAK,aAAa,EAAE,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,cAAc,CAAC,qBAAqB,CAAC,GAAG,aAAa,CAAC;IAEtD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3D,EAAE,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,mBAAmB,CAAC,kBAAkB,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;IAE9D,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,+EAA+E;IACjF,CAAC;AACH,CAAC"}
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Auto-generated AGENTS.md content
|
|
3
3
|
* DO NOT EDIT MANUALLY - run 'pnpm generate:hooks-docs' to regenerate
|
|
4
4
|
*/
|
|
5
|
-
export declare const AGENTS_MD = "# 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: 2026-02-21*\n";
|
|
5
|
+
export declare const AGENTS_MD = "# 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.\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 (registry id, e.g. claude, codex, 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: 2026-02-24*\n";
|
|
6
6
|
//# sourceMappingURL=generated-agents-doc.d.ts.map
|
|
@@ -10,7 +10,7 @@ This document contains everything an AI agent needs to create, modify, and under
|
|
|
10
10
|
|
|
11
11
|
## What You're Working On
|
|
12
12
|
|
|
13
|
-
You 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
|
|
13
|
+
You 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.
|
|
14
14
|
|
|
15
15
|
## Your Goal
|
|
16
16
|
|
|
@@ -79,7 +79,7 @@ DMUX_SERVER_PORT="3142" # HTTP server port
|
|
|
79
79
|
DMUX_PANE_ID="dmux-1234567890" # dmux pane identifier
|
|
80
80
|
DMUX_SLUG="fix-auth-bug" # Branch/worktree name
|
|
81
81
|
DMUX_PROMPT="Fix authentication bug" # User's prompt
|
|
82
|
-
DMUX_AGENT="claude" # Agent type (claude
|
|
82
|
+
DMUX_AGENT="claude" # Agent type (registry id, e.g. claude, codex, opencode)
|
|
83
83
|
DMUX_TMUX_PANE_ID="%38" # tmux pane ID
|
|
84
84
|
\`\`\`
|
|
85
85
|
|
|
@@ -425,6 +425,6 @@ When creating a new hook:
|
|
|
425
425
|
---
|
|
426
426
|
|
|
427
427
|
*This documentation was auto-generated from dmux source code.*
|
|
428
|
-
*Version: 2026-02-
|
|
428
|
+
*Version: 2026-02-24*
|
|
429
429
|
`;
|
|
430
430
|
//# sourceMappingURL=generated-agents-doc.js.map
|
|
@@ -1,15 +1,8 @@
|
|
|
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
1
|
/**
|
|
9
2
|
* Main documentation - gets written as both AGENTS.md and CLAUDE.md
|
|
10
3
|
* Different agents look for different filenames, but content is identical
|
|
11
4
|
*/
|
|
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: 2026-02-21*\n";
|
|
5
|
+
export declare const HOOKS_DOCUMENTATION: string;
|
|
13
6
|
/**
|
|
14
7
|
* README for the .dmux-hooks/ directory
|
|
15
8
|
*/
|
|
@@ -17,7 +10,7 @@ export declare const HOOKS_README = "# dmux Hooks\n\nThis directory contains hoo
|
|
|
17
10
|
/**
|
|
18
11
|
* Example: worktree_created hook
|
|
19
12
|
*/
|
|
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#
|
|
13
|
+
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# Keep existing git author identity.\n# Do not set git user.name/user.email in this hook.\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
14
|
/**
|
|
22
15
|
* Example: run_dev hook
|
|
23
16
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooksDocs.d.ts","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hooksDocs.d.ts","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,YAAY,03CAqDxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,2sCAsCpC,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"}
|
package/dist/utils/hooksDocs.js
CHANGED
|
@@ -3,9 +3,31 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This file contains all documentation that gets written to .dmux-hooks/
|
|
5
5
|
* when the directory is initialized. The AGENTS_MD content is auto-generated
|
|
6
|
-
* and imported from generated-agents-doc.ts
|
|
6
|
+
* and imported from generated-agents-doc.ts when available.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
const AGENTS_MD_FALLBACK = `# dmux Hooks
|
|
9
|
+
|
|
10
|
+
Full AGENTS.md hook documentation has not been generated in this checkout yet.
|
|
11
|
+
|
|
12
|
+
Run:
|
|
13
|
+
|
|
14
|
+
\`\`\`bash
|
|
15
|
+
pnpm run generate:hooks-docs
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
Then restart dmux.
|
|
19
|
+
`;
|
|
20
|
+
let AGENTS_MD;
|
|
21
|
+
const GENERATED_AGENTS_DOC_MODULE = './generated-agents-doc' + '.js';
|
|
22
|
+
try {
|
|
23
|
+
const docsModule = await import(GENERATED_AGENTS_DOC_MODULE);
|
|
24
|
+
AGENTS_MD = typeof docsModule.AGENTS_MD === 'string'
|
|
25
|
+
? docsModule.AGENTS_MD
|
|
26
|
+
: AGENTS_MD_FALLBACK;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
AGENTS_MD = AGENTS_MD_FALLBACK;
|
|
30
|
+
}
|
|
9
31
|
/**
|
|
10
32
|
* Main documentation - gets written as both AGENTS.md and CLAUDE.md
|
|
11
33
|
* Different agents look for different filenames, but content is identical
|
|
@@ -101,10 +123,8 @@ if [ -f "$DMUX_ROOT/.env.local" ]; then
|
|
|
101
123
|
cp "$DMUX_ROOT/.env.local" "$DMUX_WORKTREE_PATH/.env.local"
|
|
102
124
|
fi
|
|
103
125
|
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
git config user.name "dmux-agent/$DMUX_SLUG"
|
|
107
|
-
git config user.email "agent@dmux.local"
|
|
126
|
+
# Keep existing git author identity.
|
|
127
|
+
# Do not set git user.name/user.email in this hook.
|
|
108
128
|
|
|
109
129
|
# Create a log entry
|
|
110
130
|
echo "[\$(date)] Created worktree: $DMUX_SLUG | Agent: $DMUX_AGENT | Prompt: $DMUX_PROMPT" \\
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooksDocs.js","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"hooksDocs.js","sourceRoot":"","sources":["../../src/utils/hooksDocs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;;;CAW1B,CAAC;AAEF,IAAI,SAAiB,CAAC;AACtB,MAAM,2BAA2B,GAAG,wBAAwB,GAAG,KAAK,CAAC;AACrE,IAAI,CAAC;IACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC7D,SAAS,GAAG,OAAO,UAAU,CAAC,SAAS,KAAK,QAAQ;QAClD,CAAC,CAAC,UAAU,CAAC,SAAS;QACtB,CAAC,CAAC,kBAAkB,CAAC;AACzB,CAAC;AAAC,MAAM,CAAC;IACP,SAAS,GAAG,kBAAkB,CAAC;AACjC,CAAC;AAED;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCvC,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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { DmuxPane } from '../types.js';
|
|
2
|
+
import { type AgentName } from './agentLaunch.js';
|
|
2
3
|
export interface CreatePaneOptions {
|
|
3
4
|
prompt: string;
|
|
4
|
-
agent?:
|
|
5
|
+
agent?: AgentName;
|
|
5
6
|
slugSuffix?: string;
|
|
6
7
|
slugBase?: string;
|
|
7
8
|
projectName: string;
|
|
8
9
|
existingPanes: DmuxPane[];
|
|
9
10
|
projectRoot?: string;
|
|
11
|
+
skipAgentSelection?: boolean;
|
|
10
12
|
sessionConfigPath?: string;
|
|
11
13
|
sessionProjectRoot?: string;
|
|
12
14
|
}
|
|
@@ -18,5 +20,9 @@ export interface CreatePaneResult {
|
|
|
18
20
|
* Core pane creation logic that can be used by both TUI and API
|
|
19
21
|
* Returns the newly created pane and whether agent choice is needed
|
|
20
22
|
*/
|
|
21
|
-
export declare function createPane(options: CreatePaneOptions, availableAgents:
|
|
23
|
+
export declare function createPane(options: CreatePaneOptions, availableAgents: AgentName[]): Promise<CreatePaneResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Auto-approve Claude trust prompts
|
|
26
|
+
*/
|
|
27
|
+
export declare function autoApproveTrustPrompt(paneInfo: string, prompt: string): Promise<void>;
|
|
22
28
|
//# sourceMappingURL=paneCreation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paneCreation.d.ts","sourceRoot":"","sources":["../../src/utils/paneCreation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"paneCreation.d.ts","sourceRoot":"","sources":["../../src/utils/paneCreation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAcxD,OAAO,EAUL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAU1B,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,QAAQ,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,EAC1B,eAAe,EAAE,SAAS,EAAE,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAye3B;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAsHf"}
|
|
@@ -10,10 +10,12 @@ import { triggerHook, initializeHooksDirectory } from './hooks.js';
|
|
|
10
10
|
import { TMUX_LAYOUT_APPLY_DELAY, TMUX_SPLIT_DELAY } from '../constants/timing.js';
|
|
11
11
|
import { atomicWriteJsonSync } from './atomicWrite.js';
|
|
12
12
|
import { LogService } from '../services/LogService.js';
|
|
13
|
-
import { appendSlugSuffix,
|
|
13
|
+
import { appendSlugSuffix, buildAgentCommand, buildInitialPromptCommand, getAgentProcessName, getPromptTransport, getSendKeysPostPasteDelayMs, getSendKeysPrePrompt, getSendKeysReadyDelayMs, getSendKeysSubmit, } from './agentLaunch.js';
|
|
14
14
|
import { buildWorktreePaneTitle } from './paneTitle.js';
|
|
15
15
|
import { buildPromptReadAndDeleteSnippet, writePromptFile, } from './promptStore.js';
|
|
16
|
+
import { ensureGeminiFolderTrusted } from './geminiTrust.js';
|
|
16
17
|
import { isValidBranchName } from './git.js';
|
|
18
|
+
import { sendPromptViaTmux } from './agentPromptDispatch.js';
|
|
17
19
|
async function waitForPaneReady(tmuxService, paneId, timeoutMs = 600) {
|
|
18
20
|
const start = Date.now();
|
|
19
21
|
while ((Date.now() - start) < timeoutMs) {
|
|
@@ -28,7 +30,7 @@ async function waitForPaneReady(tmuxService, paneId, timeoutMs = 600) {
|
|
|
28
30
|
* Returns the newly created pane and whether agent choice is needed
|
|
29
31
|
*/
|
|
30
32
|
export async function createPane(options, availableAgents) {
|
|
31
|
-
const { prompt, projectName, existingPanes, slugSuffix, slugBase, sessionConfigPath: optionsSessionConfigPath, sessionProjectRoot: optionsSessionProjectRoot, } = options;
|
|
33
|
+
const { prompt, projectName, existingPanes, slugSuffix, slugBase, skipAgentSelection = false, sessionConfigPath: optionsSessionConfigPath, sessionProjectRoot: optionsSessionProjectRoot, } = options;
|
|
32
34
|
let { agent, projectRoot: optionsProjectRoot } = options;
|
|
33
35
|
// Load settings to check for default agent and autopilot
|
|
34
36
|
const { SettingsManager } = await import('./settingsManager.js');
|
|
@@ -68,15 +70,15 @@ export async function createPane(options, availableAgents) {
|
|
|
68
70
|
const sessionProjectRoot = optionsSessionProjectRoot
|
|
69
71
|
|| (optionsSessionConfigPath ? path.dirname(path.dirname(optionsSessionConfigPath)) : projectRoot);
|
|
70
72
|
const paneProjectName = path.basename(projectRoot);
|
|
71
|
-
// If no agent specified, check settings for default agent
|
|
72
|
-
if (!agent && settings.defaultAgent) {
|
|
73
|
+
// If no agent specified, check settings for default agent unless caller explicitly disabled auto-selection.
|
|
74
|
+
if (!agent && !skipAgentSelection && settings.defaultAgent) {
|
|
73
75
|
// Only use default if it's available
|
|
74
76
|
if (availableAgents.includes(settings.defaultAgent)) {
|
|
75
77
|
agent = settings.defaultAgent;
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
// Determine if we need agent choice
|
|
79
|
-
if (!agent && availableAgents.length > 1) {
|
|
81
|
+
if (!agent && !skipAgentSelection && availableAgents.length > 1) {
|
|
80
82
|
// Need to ask which agent to use
|
|
81
83
|
return {
|
|
82
84
|
pane: null,
|
|
@@ -84,7 +86,7 @@ export async function createPane(options, availableAgents) {
|
|
|
84
86
|
};
|
|
85
87
|
}
|
|
86
88
|
// Auto-select agent if only one is available or if not specified
|
|
87
|
-
if (!agent && availableAgents.length === 1) {
|
|
89
|
+
if (!agent && !skipAgentSelection && availableAgents.length === 1) {
|
|
88
90
|
agent = availableAgents[0];
|
|
89
91
|
}
|
|
90
92
|
// Trigger before_pane_create hook
|
|
@@ -245,18 +247,6 @@ export async function createPane(options, availableAgents) {
|
|
|
245
247
|
catch {
|
|
246
248
|
// Ignore prune errors, proceed anyway
|
|
247
249
|
}
|
|
248
|
-
// Check if branch already exists (from a deleted worktree)
|
|
249
|
-
let branchExists = false;
|
|
250
|
-
try {
|
|
251
|
-
execSync(`git show-ref --verify --quiet "refs/heads/${branchName}"`, {
|
|
252
|
-
stdio: 'pipe',
|
|
253
|
-
cwd: projectRoot,
|
|
254
|
-
});
|
|
255
|
-
branchExists = true;
|
|
256
|
-
}
|
|
257
|
-
catch {
|
|
258
|
-
// Branch doesn't exist, which is good
|
|
259
|
-
}
|
|
260
250
|
// Validate and resolve base branch for new worktrees
|
|
261
251
|
const baseBranch = settings.baseBranch || '';
|
|
262
252
|
if (baseBranch && !isValidBranchName(baseBranch)) {
|
|
@@ -273,28 +263,46 @@ export async function createPane(options, availableAgents) {
|
|
|
273
263
|
throw new Error(`Base branch "${baseBranch}" does not exist. Update the baseBranch setting to a valid branch name.`);
|
|
274
264
|
}
|
|
275
265
|
}
|
|
276
|
-
|
|
277
|
-
// - If branch exists, use it (don't create with -b)
|
|
278
|
-
// - If branch doesn't exist, create it with -b, optionally from a configured base branch
|
|
279
|
-
// - DON'T silence errors (we want to see them in the pane for debugging)
|
|
280
|
-
const startPoint = baseBranch ? ` "${baseBranch}"` : '';
|
|
281
|
-
const worktreeAddCmd = branchExists
|
|
282
|
-
? `git worktree add "${worktreePath}" "${branchName}"`
|
|
283
|
-
: `git worktree add "${worktreePath}" -b "${branchName}"${startPoint}`;
|
|
284
|
-
const worktreeCmd = `cd "${projectRoot}" && ${worktreeAddCmd} && cd "${worktreePath}"`;
|
|
285
|
-
// Send the git worktree command (auto-quoted by sendShellCommand)
|
|
286
|
-
await tmuxService.sendShellCommand(paneInfo, worktreeCmd);
|
|
287
|
-
await tmuxService.sendTmuxKeys(paneInfo, 'Enter');
|
|
288
|
-
// Wait for worktree to actually exist on the filesystem
|
|
266
|
+
const maxWorktreeAttempts = 3;
|
|
289
267
|
const maxWaitTime = 5000; // 5 seconds max
|
|
290
268
|
const checkInterval = 100; // Check every 100ms
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
269
|
+
let worktreeCreated = fs.existsSync(worktreePath);
|
|
270
|
+
for (let attempt = 1; attempt <= maxWorktreeAttempts && !worktreeCreated; attempt++) {
|
|
271
|
+
// Check if branch already exists (from a deleted worktree or a previous attempt)
|
|
272
|
+
let branchExists = false;
|
|
273
|
+
try {
|
|
274
|
+
execSync(`git show-ref --verify --quiet "refs/heads/${branchName}"`, {
|
|
275
|
+
stdio: 'pipe',
|
|
276
|
+
cwd: projectRoot,
|
|
277
|
+
});
|
|
278
|
+
branchExists = true;
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// Branch doesn't exist yet
|
|
282
|
+
}
|
|
283
|
+
// Build worktree command:
|
|
284
|
+
// - If branch exists, use it (don't create with -b)
|
|
285
|
+
// - If branch doesn't exist, create it with -b, optionally from a configured base branch
|
|
286
|
+
const startPoint = baseBranch ? ` "${baseBranch}"` : '';
|
|
287
|
+
const worktreeAddCmd = branchExists
|
|
288
|
+
? `git worktree add "${worktreePath}" "${branchName}"`
|
|
289
|
+
: `git worktree add "${worktreePath}" -b "${branchName}"${startPoint}`;
|
|
290
|
+
const worktreeCmd = `cd "${projectRoot}" && ${worktreeAddCmd} && cd "${worktreePath}"`;
|
|
291
|
+
// Send the git worktree command (auto-quoted by sendShellCommand)
|
|
292
|
+
await tmuxService.sendShellCommand(paneInfo, worktreeCmd);
|
|
293
|
+
await tmuxService.sendTmuxKeys(paneInfo, 'Enter');
|
|
294
|
+
const startTime = Date.now();
|
|
295
|
+
while (!fs.existsSync(worktreePath) && (Date.now() - startTime) < maxWaitTime) {
|
|
296
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
297
|
+
}
|
|
298
|
+
worktreeCreated = fs.existsSync(worktreePath);
|
|
299
|
+
if (!worktreeCreated && attempt < maxWorktreeAttempts) {
|
|
300
|
+
await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
|
|
301
|
+
}
|
|
294
302
|
}
|
|
295
303
|
// Verify worktree was created successfully
|
|
296
|
-
if (!
|
|
297
|
-
throw new Error(`Worktree directory not created at ${worktreePath} after ${
|
|
304
|
+
if (!worktreeCreated) {
|
|
305
|
+
throw new Error(`Worktree directory not created at ${worktreePath} after ${maxWorktreeAttempts} attempts`);
|
|
298
306
|
}
|
|
299
307
|
// Give a bit more time for git to finish setting up the worktree
|
|
300
308
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
@@ -315,47 +323,26 @@ export async function createPane(options, availableAgents) {
|
|
|
315
323
|
}
|
|
316
324
|
// Launch agent if specified
|
|
317
325
|
const hasInitialPrompt = !!(prompt && prompt.trim());
|
|
318
|
-
if (agent
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
326
|
+
if (agent) {
|
|
327
|
+
if (agent === 'gemini') {
|
|
328
|
+
const geminiWorkspacePath = fs.existsSync(worktreePath)
|
|
329
|
+
? worktreePath
|
|
330
|
+
: projectRoot;
|
|
331
|
+
ensureGeminiFolderTrusted(geminiWorkspacePath);
|
|
332
|
+
}
|
|
333
|
+
const promptTransport = getPromptTransport(agent);
|
|
334
|
+
const shouldSendPromptViaTmux = hasInitialPrompt && promptTransport === 'send-keys';
|
|
335
|
+
let baselineCommand;
|
|
336
|
+
if (shouldSendPromptViaTmux) {
|
|
324
337
|
try {
|
|
325
|
-
|
|
338
|
+
baselineCommand = await tmuxService.getPaneCurrentCommand(paneInfo);
|
|
326
339
|
}
|
|
327
340
|
catch {
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
if (promptFilePath) {
|
|
331
|
-
const promptBootstrap = buildPromptReadAndDeleteSnippet(promptFilePath);
|
|
332
|
-
claudeCmd = `${promptBootstrap}; claude "$DMUX_PROMPT_CONTENT"${permissionSuffix}`;
|
|
341
|
+
baselineCommand = undefined;
|
|
333
342
|
}
|
|
334
|
-
else {
|
|
335
|
-
const escapedPrompt = prompt
|
|
336
|
-
.replace(/\\/g, '\\\\')
|
|
337
|
-
.replace(/"/g, '\\"')
|
|
338
|
-
.replace(/`/g, '\\`')
|
|
339
|
-
.replace(/\$/g, '\\$');
|
|
340
|
-
claudeCmd = `claude "${escapedPrompt}"${permissionSuffix}`;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
claudeCmd = `claude${permissionSuffix}`;
|
|
345
343
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
await tmuxService.sendTmuxKeys(paneInfo, 'Enter');
|
|
349
|
-
// Auto-approve trust prompts for Claude (workspace trust, not edit permissions)
|
|
350
|
-
autoApproveTrustPrompt(paneInfo, prompt).catch(() => {
|
|
351
|
-
// Ignore errors in background monitoring
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
else if (agent === 'codex') {
|
|
355
|
-
const permissionFlags = getPermissionFlags('codex', settings.permissionMode);
|
|
356
|
-
const permissionSuffix = permissionFlags ? ` ${permissionFlags}` : '';
|
|
357
|
-
let codexCmd;
|
|
358
|
-
if (hasInitialPrompt) {
|
|
344
|
+
let launchCommand;
|
|
345
|
+
if (hasInitialPrompt && !shouldSendPromptViaTmux) {
|
|
359
346
|
let promptFilePath = null;
|
|
360
347
|
try {
|
|
361
348
|
promptFilePath = await writePromptFile(projectRoot, slug, prompt);
|
|
@@ -365,7 +352,7 @@ export async function createPane(options, availableAgents) {
|
|
|
365
352
|
}
|
|
366
353
|
if (promptFilePath) {
|
|
367
354
|
const promptBootstrap = buildPromptReadAndDeleteSnippet(promptFilePath);
|
|
368
|
-
|
|
355
|
+
launchCommand = `${promptBootstrap}; ${buildInitialPromptCommand(agent, '"$DMUX_PROMPT_CONTENT"', settings.permissionMode)}`;
|
|
369
356
|
}
|
|
370
357
|
else {
|
|
371
358
|
const escapedPrompt = prompt
|
|
@@ -373,43 +360,33 @@ export async function createPane(options, availableAgents) {
|
|
|
373
360
|
.replace(/"/g, '\\"')
|
|
374
361
|
.replace(/`/g, '\\`')
|
|
375
362
|
.replace(/\$/g, '\\$');
|
|
376
|
-
|
|
363
|
+
launchCommand = buildInitialPromptCommand(agent, `"${escapedPrompt}"`, settings.permissionMode);
|
|
377
364
|
}
|
|
378
365
|
}
|
|
379
366
|
else {
|
|
380
|
-
|
|
367
|
+
launchCommand = buildAgentCommand(agent, settings.permissionMode);
|
|
381
368
|
}
|
|
382
|
-
await tmuxService.sendShellCommand(paneInfo,
|
|
369
|
+
await tmuxService.sendShellCommand(paneInfo, launchCommand);
|
|
383
370
|
await tmuxService.sendTmuxKeys(paneInfo, 'Enter');
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const promptBootstrap = buildPromptReadAndDeleteSnippet(promptFilePath);
|
|
397
|
-
opencodeCmd = `${promptBootstrap}; opencode --prompt "$DMUX_PROMPT_CONTENT"`;
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
const escapedPrompt = prompt
|
|
401
|
-
.replace(/\\/g, '\\\\')
|
|
402
|
-
.replace(/"/g, '\\"')
|
|
403
|
-
.replace(/`/g, '\\`')
|
|
404
|
-
.replace(/\$/g, '\\$');
|
|
405
|
-
opencodeCmd = `opencode --prompt "${escapedPrompt}"`;
|
|
406
|
-
}
|
|
371
|
+
if (shouldSendPromptViaTmux) {
|
|
372
|
+
await sendPromptViaTmux({
|
|
373
|
+
paneId: paneInfo,
|
|
374
|
+
prompt,
|
|
375
|
+
tmuxService,
|
|
376
|
+
expectedCommand: getAgentProcessName(agent),
|
|
377
|
+
baselineCommand,
|
|
378
|
+
prePromptKeys: getSendKeysPrePrompt(agent),
|
|
379
|
+
submitKeys: getSendKeysSubmit(agent),
|
|
380
|
+
postPasteDelayMs: getSendKeysPostPasteDelayMs(agent),
|
|
381
|
+
readyDelayMs: getSendKeysReadyDelayMs(agent),
|
|
382
|
+
});
|
|
407
383
|
}
|
|
408
|
-
|
|
409
|
-
|
|
384
|
+
if (agent === 'claude') {
|
|
385
|
+
// Auto-approve trust prompts for Claude (workspace trust, not edit permissions)
|
|
386
|
+
autoApproveTrustPrompt(paneInfo, prompt).catch(() => {
|
|
387
|
+
// Ignore errors in background monitoring
|
|
388
|
+
});
|
|
410
389
|
}
|
|
411
|
-
await tmuxService.sendShellCommand(paneInfo, opencodeCmd);
|
|
412
|
-
await tmuxService.sendTmuxKeys(paneInfo, 'Enter');
|
|
413
390
|
}
|
|
414
391
|
// Keep focus on the new pane
|
|
415
392
|
await tmuxService.selectPane(paneInfo);
|
|
@@ -451,7 +428,7 @@ export async function createPane(options, availableAgents) {
|
|
|
451
428
|
await tmuxService.selectPane(originalPaneId);
|
|
452
429
|
// Re-set the title for the dmux pane
|
|
453
430
|
try {
|
|
454
|
-
await tmuxService.setPaneTitle(originalPaneId,
|
|
431
|
+
await tmuxService.setPaneTitle(originalPaneId, "dmux");
|
|
455
432
|
}
|
|
456
433
|
catch {
|
|
457
434
|
// Ignore if setting title fails
|
|
@@ -464,7 +441,7 @@ export async function createPane(options, availableAgents) {
|
|
|
464
441
|
/**
|
|
465
442
|
* Auto-approve Claude trust prompts
|
|
466
443
|
*/
|
|
467
|
-
async function autoApproveTrustPrompt(paneInfo, prompt) {
|
|
444
|
+
export async function autoApproveTrustPrompt(paneInfo, prompt) {
|
|
468
445
|
// Wait longer for Claude to start up before checking for prompts
|
|
469
446
|
await new Promise((resolve) => setTimeout(resolve, 1200));
|
|
470
447
|
const maxChecks = 100; // 100 checks * 100ms = 10 seconds total
|