clasp-ai 0.0.1 → 0.7.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/LICENSE +21 -0
- package/README.md +491 -34
- package/bin/clasp-wrapper.js +40 -0
- package/package.json +39 -24
- package/scripts/install.js +178 -0
- package/scripts/launcher.sh +151 -0
- package/scripts/prepack.js +31 -0
- package/scripts/start-clasp-session.sh +90 -0
- package/scripts/stream-parser.sh +304 -0
- package/.claude-flow/metrics/agent-metrics.json +0 -1
- package/.claude-flow/metrics/performance.json +0 -87
- package/.claude-flow/metrics/task-metrics.json +0 -10
- package/bin/clasp +0 -22
- package/postinstall.js +0 -4
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLASP Installation Script
|
|
5
|
+
* Downloads the pre-built Go binary for the current platform
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const http = require('http');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
|
|
15
|
+
const VERSION = '0.2.1';
|
|
16
|
+
const REPO = 'jedarden/CLASP';
|
|
17
|
+
const BINARY_NAME = 'clasp';
|
|
18
|
+
|
|
19
|
+
// Platform mappings
|
|
20
|
+
const PLATFORM_MAP = {
|
|
21
|
+
darwin: 'darwin',
|
|
22
|
+
linux: 'linux',
|
|
23
|
+
win32: 'windows'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const ARCH_MAP = {
|
|
27
|
+
x64: 'amd64',
|
|
28
|
+
arm64: 'arm64'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function getPlatformInfo() {
|
|
32
|
+
const platform = PLATFORM_MAP[os.platform()];
|
|
33
|
+
const arch = ARCH_MAP[os.arch()];
|
|
34
|
+
|
|
35
|
+
if (!platform) {
|
|
36
|
+
throw new Error(`Unsupported platform: ${os.platform()}`);
|
|
37
|
+
}
|
|
38
|
+
if (!arch) {
|
|
39
|
+
throw new Error(`Unsupported architecture: ${os.arch()}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { platform, arch };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getBinaryName(platform) {
|
|
46
|
+
return platform === 'windows' ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getDownloadUrl(platform, arch) {
|
|
50
|
+
const ext = platform === 'windows' ? '.exe' : '';
|
|
51
|
+
const filename = `clasp-${platform}-${arch}${ext}`;
|
|
52
|
+
return `https://github.com/${REPO}/releases/download/v${VERSION}/${filename}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function download(url, dest) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const file = fs.createWriteStream(dest);
|
|
58
|
+
const protocol = url.startsWith('https') ? https : http;
|
|
59
|
+
|
|
60
|
+
const request = protocol.get(url, (response) => {
|
|
61
|
+
// Handle redirects
|
|
62
|
+
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
63
|
+
file.close();
|
|
64
|
+
fs.unlinkSync(dest);
|
|
65
|
+
return download(response.headers.location, dest)
|
|
66
|
+
.then(resolve)
|
|
67
|
+
.catch(reject);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (response.statusCode !== 200) {
|
|
71
|
+
file.close();
|
|
72
|
+
fs.unlinkSync(dest);
|
|
73
|
+
reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
response.pipe(file);
|
|
78
|
+
|
|
79
|
+
file.on('finish', () => {
|
|
80
|
+
file.close();
|
|
81
|
+
resolve();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
request.on('error', (err) => {
|
|
86
|
+
file.close();
|
|
87
|
+
fs.unlink(dest, () => {}); // Delete partial file
|
|
88
|
+
reject(err);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function buildFromSource() {
|
|
94
|
+
console.log('[CLASP] Pre-built binary not available, building from source...');
|
|
95
|
+
|
|
96
|
+
// Check if Go is installed
|
|
97
|
+
try {
|
|
98
|
+
execSync('go version', { stdio: 'pipe' });
|
|
99
|
+
} catch {
|
|
100
|
+
throw new Error(
|
|
101
|
+
'Go is not installed. Please install Go from https://go.dev/dl/ or download a pre-built binary from ' +
|
|
102
|
+
`https://github.com/${REPO}/releases`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const packageDir = path.dirname(__dirname);
|
|
107
|
+
const binDir = path.join(packageDir, 'bin');
|
|
108
|
+
|
|
109
|
+
if (!fs.existsSync(binDir)) {
|
|
110
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log('[CLASP] Building binary...');
|
|
114
|
+
execSync(`go build -o ${path.join(binDir, BINARY_NAME)} ./cmd/clasp`, {
|
|
115
|
+
cwd: packageDir,
|
|
116
|
+
stdio: 'inherit'
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
console.log('[CLASP] Build complete!');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function main() {
|
|
123
|
+
console.log(`[CLASP] Installing CLASP v${VERSION}...`);
|
|
124
|
+
|
|
125
|
+
const { platform, arch } = getPlatformInfo();
|
|
126
|
+
const binaryName = getBinaryName(platform);
|
|
127
|
+
const binDir = path.join(path.dirname(__dirname), 'bin');
|
|
128
|
+
const binaryPath = path.join(binDir, binaryName);
|
|
129
|
+
|
|
130
|
+
// Create bin directory if it doesn't exist
|
|
131
|
+
if (!fs.existsSync(binDir)) {
|
|
132
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check if binary already exists and is correct version
|
|
136
|
+
if (fs.existsSync(binaryPath)) {
|
|
137
|
+
try {
|
|
138
|
+
const versionOutput = execSync(`"${binaryPath}" -version`, { encoding: 'utf8' });
|
|
139
|
+
if (versionOutput.includes(VERSION)) {
|
|
140
|
+
console.log(`[CLASP] CLASP v${VERSION} is already installed.`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
// Version check failed, proceed with download
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const url = getDownloadUrl(platform, arch);
|
|
149
|
+
console.log(`[CLASP] Downloading from ${url}...`);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
await download(url, binaryPath);
|
|
153
|
+
|
|
154
|
+
// Make executable on Unix
|
|
155
|
+
if (platform !== 'windows') {
|
|
156
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(`[CLASP] Successfully installed to ${binaryPath}`);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.warn(`[CLASP] Download failed: ${err.message}`);
|
|
162
|
+
|
|
163
|
+
// Try building from source
|
|
164
|
+
try {
|
|
165
|
+
await buildFromSource();
|
|
166
|
+
} catch (buildErr) {
|
|
167
|
+
console.error(`[CLASP] Installation failed: ${buildErr.message}`);
|
|
168
|
+
console.error('[CLASP] Please ensure Go is installed or download the binary manually from:');
|
|
169
|
+
console.error(`[CLASP] https://github.com/${REPO}/releases`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
main().catch((err) => {
|
|
176
|
+
console.error(`[CLASP] Installation error: ${err.message}`);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CLASP Autonomous Agent Launcher
|
|
3
|
+
# Runs Claude Code in a continuous loop with the CLASP development prompt
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Configuration
|
|
8
|
+
WORKSPACE="/workspaces/ord-options-testing"
|
|
9
|
+
CLASP_DIR="$WORKSPACE/CLASP"
|
|
10
|
+
PROMPT_FILE="$CLASP_DIR/prompt.md"
|
|
11
|
+
LOG_DIR="$WORKSPACE/.clasp/logs"
|
|
12
|
+
LOOP_DELAY=5 # Seconds between iterations
|
|
13
|
+
PARSER_SCRIPT="$CLASP_DIR/scripts/stream-parser.sh"
|
|
14
|
+
|
|
15
|
+
# Colors
|
|
16
|
+
RED='\033[0;31m'
|
|
17
|
+
GREEN='\033[0;32m'
|
|
18
|
+
YELLOW='\033[1;33m'
|
|
19
|
+
BLUE='\033[0;34m'
|
|
20
|
+
CYAN='\033[0;36m'
|
|
21
|
+
MAGENTA='\033[0;35m'
|
|
22
|
+
NC='\033[0m' # No Color
|
|
23
|
+
BOLD='\033[1m'
|
|
24
|
+
|
|
25
|
+
# Iteration counter
|
|
26
|
+
ITERATION=0
|
|
27
|
+
|
|
28
|
+
# Log file for this session
|
|
29
|
+
SESSION_ID=$(date +%Y%m%d_%H%M%S)
|
|
30
|
+
SESSION_LOG="$LOG_DIR/session_$SESSION_ID.jsonl"
|
|
31
|
+
|
|
32
|
+
echo -e "${MAGENTA}${BOLD}"
|
|
33
|
+
echo "╔══════════════════════════════════════════════════════════════════╗"
|
|
34
|
+
echo "║ CLASP - Claude Language Agent Super Proxy ║"
|
|
35
|
+
echo "║ Autonomous Development Agent ║"
|
|
36
|
+
echo "╚══════════════════════════════════════════════════════════════════╝"
|
|
37
|
+
echo -e "${NC}"
|
|
38
|
+
echo ""
|
|
39
|
+
echo -e "${BLUE}Workspace:${NC} $WORKSPACE"
|
|
40
|
+
echo -e "${BLUE}CLASP Dir:${NC} $CLASP_DIR"
|
|
41
|
+
echo -e "${BLUE}Session:${NC} $SESSION_ID"
|
|
42
|
+
echo -e "${BLUE}Log:${NC} $SESSION_LOG"
|
|
43
|
+
echo ""
|
|
44
|
+
|
|
45
|
+
# Ensure directories exist
|
|
46
|
+
mkdir -p "$LOG_DIR"
|
|
47
|
+
|
|
48
|
+
# Check if prompt file exists
|
|
49
|
+
if [ ! -f "$PROMPT_FILE" ]; then
|
|
50
|
+
echo -e "${RED}Error: Prompt file not found at $PROMPT_FILE${NC}"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Check if parser script exists and is executable
|
|
55
|
+
if [ ! -x "$PARSER_SCRIPT" ]; then
|
|
56
|
+
echo -e "${YELLOW}Warning: Parser script not found or not executable${NC}"
|
|
57
|
+
echo -e "${YELLOW}Output will be raw JSON${NC}"
|
|
58
|
+
USE_PARSER=false
|
|
59
|
+
else
|
|
60
|
+
USE_PARSER=true
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Function to print iteration header
|
|
64
|
+
print_header() {
|
|
65
|
+
local iter=$1
|
|
66
|
+
local timestamp=$(date '+%Y-%m-%d %H:%M:%S %Z')
|
|
67
|
+
|
|
68
|
+
echo ""
|
|
69
|
+
echo -e "${GREEN}${BOLD}"
|
|
70
|
+
echo "┌──────────────────────────────────────────────────────────────────┐"
|
|
71
|
+
printf "│ Iteration: %-5d │\n" "$iter"
|
|
72
|
+
printf "│ Time: %-55s │\n" "$timestamp"
|
|
73
|
+
echo "└──────────────────────────────────────────────────────────────────┘"
|
|
74
|
+
echo -e "${NC}"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Function to print iteration footer
|
|
78
|
+
print_footer() {
|
|
79
|
+
local iter=$1
|
|
80
|
+
local duration=$2
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
echo -e "${YELLOW}────────────────────────────────────────────────────────────────────${NC}"
|
|
84
|
+
echo -e "${YELLOW}Iteration $iter completed in ${duration}s${NC}"
|
|
85
|
+
echo -e "${YELLOW}Waiting ${LOOP_DELAY}s before next iteration...${NC}"
|
|
86
|
+
echo -e "${YELLOW}────────────────────────────────────────────────────────────────────${NC}"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Trap for clean exit
|
|
90
|
+
cleanup() {
|
|
91
|
+
echo ""
|
|
92
|
+
echo -e "${RED}${BOLD}Shutting down CLASP agent...${NC}"
|
|
93
|
+
echo -e "${BLUE}Total iterations completed: $ITERATION${NC}"
|
|
94
|
+
exit 0
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
trap cleanup SIGINT SIGTERM
|
|
98
|
+
|
|
99
|
+
# Main loop
|
|
100
|
+
echo -e "${GREEN}Starting autonomous development loop...${NC}"
|
|
101
|
+
echo -e "${CYAN}Press Ctrl+C to stop${NC}"
|
|
102
|
+
echo ""
|
|
103
|
+
|
|
104
|
+
while true; do
|
|
105
|
+
ITERATION=$((ITERATION + 1))
|
|
106
|
+
START_TIME=$(date +%s)
|
|
107
|
+
|
|
108
|
+
# Print iteration header
|
|
109
|
+
print_header $ITERATION
|
|
110
|
+
|
|
111
|
+
# Log iteration start
|
|
112
|
+
echo "{\"event\":\"iteration_start\",\"iteration\":$ITERATION,\"timestamp\":\"$(date -Iseconds)\"}" >> "$SESSION_LOG"
|
|
113
|
+
|
|
114
|
+
# Read the prompt
|
|
115
|
+
PROMPT=$(cat "$PROMPT_FILE")
|
|
116
|
+
|
|
117
|
+
# Run Claude Code headless with stream-json
|
|
118
|
+
echo -e "${BLUE}Running Claude Code...${NC}"
|
|
119
|
+
echo ""
|
|
120
|
+
|
|
121
|
+
if [ "$USE_PARSER" = true ]; then
|
|
122
|
+
# Pipe through parser for human-readable output
|
|
123
|
+
claude --dangerously-skip-permissions \
|
|
124
|
+
--output-format stream-json \
|
|
125
|
+
--verbose \
|
|
126
|
+
--print \
|
|
127
|
+
-p "$PROMPT" \
|
|
128
|
+
2>&1 | tee -a "$SESSION_LOG" | "$PARSER_SCRIPT"
|
|
129
|
+
else
|
|
130
|
+
# Raw JSON output
|
|
131
|
+
claude --dangerously-skip-permissions \
|
|
132
|
+
--output-format stream-json \
|
|
133
|
+
--verbose \
|
|
134
|
+
--print \
|
|
135
|
+
-p "$PROMPT" \
|
|
136
|
+
2>&1 | tee -a "$SESSION_LOG"
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# Calculate duration
|
|
140
|
+
END_TIME=$(date +%s)
|
|
141
|
+
DURATION=$((END_TIME - START_TIME))
|
|
142
|
+
|
|
143
|
+
# Log iteration end
|
|
144
|
+
echo "{\"event\":\"iteration_end\",\"iteration\":$ITERATION,\"duration_secs\":$DURATION,\"timestamp\":\"$(date -Iseconds)\"}" >> "$SESSION_LOG"
|
|
145
|
+
|
|
146
|
+
# Print iteration footer
|
|
147
|
+
print_footer $ITERATION $DURATION
|
|
148
|
+
|
|
149
|
+
# Wait before next iteration
|
|
150
|
+
sleep $LOOP_DELAY
|
|
151
|
+
done
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLASP Prepack Script
|
|
5
|
+
* Prepares the package for npm publish by removing binaries
|
|
6
|
+
* (users will download their platform-specific binary on install)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const binDir = path.join(path.dirname(__dirname), 'bin');
|
|
13
|
+
|
|
14
|
+
// List of files to keep in bin/
|
|
15
|
+
const KEEP_FILES = ['clasp-wrapper.js'];
|
|
16
|
+
|
|
17
|
+
console.log('[CLASP] Preparing package for npm...');
|
|
18
|
+
|
|
19
|
+
// Remove compiled binaries (they'll be downloaded on install)
|
|
20
|
+
if (fs.existsSync(binDir)) {
|
|
21
|
+
const files = fs.readdirSync(binDir);
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
if (!KEEP_FILES.includes(file)) {
|
|
24
|
+
const filePath = path.join(binDir, file);
|
|
25
|
+
fs.unlinkSync(filePath);
|
|
26
|
+
console.log(`[CLASP] Removed ${file}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log('[CLASP] Package prepared successfully!');
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CLASP Tmux Session Starter
|
|
3
|
+
# Creates a tmux session using phonetic alphabet naming and starts the launcher
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Color codes for output
|
|
8
|
+
RED='\033[0;31m'
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
BLUE='\033[0;34m'
|
|
12
|
+
MAGENTA='\033[0;35m'
|
|
13
|
+
CYAN='\033[0;36m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
BOLD='\033[1m'
|
|
16
|
+
|
|
17
|
+
# Phonetic alphabet for tmux sessions (same as start.sh)
|
|
18
|
+
PHONETIC_NAMES=("alpha" "bravo" "charlie" "delta" "echo" "foxtrot" "golf" "hotel" "india" "juliet" "kilo" "lima" "mike" "november" "oscar" "papa" "quebec" "romeo" "sierra" "tango" "uniform" "victor" "whiskey" "xray" "yankee" "zulu")
|
|
19
|
+
|
|
20
|
+
# Configuration
|
|
21
|
+
WORKSPACE="/workspaces/ord-options-testing"
|
|
22
|
+
CLASP_DIR="$WORKSPACE/CLASP"
|
|
23
|
+
LAUNCHER_SCRIPT="$CLASP_DIR/scripts/launcher.sh"
|
|
24
|
+
|
|
25
|
+
# Function to find next available tmux session name
|
|
26
|
+
find_tmux_session() {
|
|
27
|
+
for name in "${PHONETIC_NAMES[@]}"; do
|
|
28
|
+
if ! tmux has-session -t "$name" 2>/dev/null; then
|
|
29
|
+
echo "$name"
|
|
30
|
+
return 0
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
# If all phonetic names are taken, use a timestamp
|
|
34
|
+
echo "clasp-$(date +%s)"
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Print banner
|
|
39
|
+
echo -e "${MAGENTA}${BOLD}"
|
|
40
|
+
echo "╔══════════════════════════════════════════════════════════════════╗"
|
|
41
|
+
echo "║ CLASP - Claude Language Agent Super Proxy ║"
|
|
42
|
+
echo "║ Tmux Session Starter ║"
|
|
43
|
+
echo "╚══════════════════════════════════════════════════════════════════╝"
|
|
44
|
+
echo -e "${NC}"
|
|
45
|
+
|
|
46
|
+
# Check if launcher script exists
|
|
47
|
+
if [ ! -x "$LAUNCHER_SCRIPT" ]; then
|
|
48
|
+
echo -e "${RED}Error: Launcher script not found or not executable at $LAUNCHER_SCRIPT${NC}"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Ensure .clasp directory exists for logs
|
|
53
|
+
mkdir -p "$WORKSPACE/.clasp/logs"
|
|
54
|
+
|
|
55
|
+
# Find available session name
|
|
56
|
+
SESSION_NAME=$(find_tmux_session)
|
|
57
|
+
|
|
58
|
+
echo -e "${BLUE}Creating tmux session:${NC} $SESSION_NAME"
|
|
59
|
+
echo -e "${BLUE}Working directory:${NC} $CLASP_DIR"
|
|
60
|
+
echo ""
|
|
61
|
+
|
|
62
|
+
# Create tmux session
|
|
63
|
+
if tmux new-session -d -s "$SESSION_NAME" -c "$CLASP_DIR" "$LAUNCHER_SCRIPT"; then
|
|
64
|
+
echo -e "${GREEN}${BOLD}✓ CLASP autonomous agent started!${NC}"
|
|
65
|
+
echo ""
|
|
66
|
+
echo -e "${CYAN}Session Details:${NC}"
|
|
67
|
+
echo -e " Name: ${BOLD}$SESSION_NAME${NC}"
|
|
68
|
+
echo -e " Launcher: $LAUNCHER_SCRIPT"
|
|
69
|
+
echo -e " Logs: $WORKSPACE/.clasp/logs/"
|
|
70
|
+
echo ""
|
|
71
|
+
echo -e "${YELLOW}Commands:${NC}"
|
|
72
|
+
echo -e " Attach: ${WHITE}tmux attach -t $SESSION_NAME${NC}"
|
|
73
|
+
echo -e " Detach: ${WHITE}Ctrl+B, D${NC} (while attached)"
|
|
74
|
+
echo -e " Kill: ${WHITE}tmux kill-session -t $SESSION_NAME${NC}"
|
|
75
|
+
echo -e " List: ${WHITE}tmux ls${NC}"
|
|
76
|
+
echo ""
|
|
77
|
+
|
|
78
|
+
# Ask if user wants to attach
|
|
79
|
+
read -p "$(echo -e ${CYAN}Attach to session now? [Y/n]: ${NC})" -n 1 -r
|
|
80
|
+
echo ""
|
|
81
|
+
if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
|
|
82
|
+
tmux attach -t "$SESSION_NAME"
|
|
83
|
+
else
|
|
84
|
+
echo -e "${GREEN}Session running in background.${NC}"
|
|
85
|
+
echo -e "${YELLOW}Run 'tmux attach -t $SESSION_NAME' to connect.${NC}"
|
|
86
|
+
fi
|
|
87
|
+
else
|
|
88
|
+
echo -e "${RED}Failed to create tmux session${NC}"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|