shellmates 0.1.2 → 0.1.3
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/lib/commands/pond.js +105 -0
- package/package.json +1 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { writeFileSync, chmodSync, existsSync } from 'fs'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import { tmpdir, homedir } from 'os'
|
|
5
|
+
import { execSync, spawnSync } from 'child_process'
|
|
6
|
+
import { readConfig, CONFIG_PATH } from '../utils/config.js'
|
|
7
|
+
import { tmuxAvailable } from '../utils/tmux.js'
|
|
8
|
+
|
|
9
|
+
const ORCHESTRATOR_CMDS = {
|
|
10
|
+
claude: (promptFile) => `claude "$(cat ${promptFile})"`,
|
|
11
|
+
gemini: (promptFile) => `gemini -p "$(cat ${promptFile})"`,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function buildPrompt(agents, project) {
|
|
15
|
+
const agentList = agents.join(', ')
|
|
16
|
+
const projectNote = project ? `The user's project is at: ${project}` : ''
|
|
17
|
+
|
|
18
|
+
return `You are the shellmates orchestrator — a coordinating AI that helps users accomplish software development goals by delegating work to specialized AI agent executors.
|
|
19
|
+
|
|
20
|
+
Your job is NOT to write code yourself. You plan, clarify, and dispatch.
|
|
21
|
+
|
|
22
|
+
Start with a single warm, brief greeting and ask the user what they want to work on today. Keep it to one or two sentences — don't explain your role, just start the conversation naturally.
|
|
23
|
+
|
|
24
|
+
When the user shares their goal:
|
|
25
|
+
1. Ask clarifying questions if needed (scope, affected files, tech stack, constraints)
|
|
26
|
+
2. Once you have enough context, break the work into discrete, self-contained tasks
|
|
27
|
+
3. Dispatch each task using the Bash tool: shellmates spawn --task "precise task description" --agent <agent>
|
|
28
|
+
4. When an executor finishes you'll receive an AGENT_PING in your terminal — review the result, then decide what comes next
|
|
29
|
+
5. Repeat until the goal is complete
|
|
30
|
+
|
|
31
|
+
Dispatch rules:
|
|
32
|
+
- Only spawn when you have a specific, actionable task — not vague intentions
|
|
33
|
+
- gemini: best for large-context work, long implementations, reading many files
|
|
34
|
+
- codex: best for sandboxed execution, isolated environments, focused rewrites
|
|
35
|
+
- You can dispatch multiple agents in parallel if tasks are truly independent
|
|
36
|
+
- Never spawn the same task twice — verify before re-dispatching
|
|
37
|
+
|
|
38
|
+
Available agents: ${agentList}
|
|
39
|
+
Dispatch command: shellmates spawn --task "..." --agent gemini|codex
|
|
40
|
+
Check sessions: shellmates status
|
|
41
|
+
${projectNote}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function pond(options) {
|
|
45
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
46
|
+
console.log(chalk.yellow('\n ~ Not initialized yet.'))
|
|
47
|
+
console.log(' Run ' + chalk.bold('shellmates init') + ' first.\n')
|
|
48
|
+
process.exit(1)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!tmuxAvailable()) {
|
|
52
|
+
console.log(chalk.red('\n ✗ tmux not found. Install: brew install tmux\n'))
|
|
53
|
+
process.exit(1)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const config = readConfig()
|
|
57
|
+
const orchestrator = config.orchestrator || 'claude'
|
|
58
|
+
const agents = config.default_agents || (config.default_agent ? [config.default_agent] : ['gemini'])
|
|
59
|
+
const project = options.project || process.cwd()
|
|
60
|
+
|
|
61
|
+
if (!ORCHESTRATOR_CMDS[orchestrator]) {
|
|
62
|
+
console.log(chalk.red(`\n ✗ Orchestrator "${orchestrator}" doesn't support pond mode yet.`))
|
|
63
|
+
console.log(chalk.dim(' Set orchestrator to "claude" in shellmates config.\n'))
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ts = Date.now()
|
|
68
|
+
const sessionName = options.session || `shellmates-pond-${ts}`
|
|
69
|
+
|
|
70
|
+
// Write prompt to temp file (avoids shell escaping issues)
|
|
71
|
+
const promptFile = join(tmpdir(), `shellmates-pond-${ts}.txt`)
|
|
72
|
+
writeFileSync(promptFile, buildPrompt(agents, project))
|
|
73
|
+
|
|
74
|
+
// Write launcher script
|
|
75
|
+
const launchFile = join(tmpdir(), `shellmates-pond-${ts}.sh`)
|
|
76
|
+
const orchCmd = ORCHESTRATOR_CMDS[orchestrator](promptFile)
|
|
77
|
+
writeFileSync(launchFile, `#!/bin/bash\ncd ${JSON.stringify(project)}\n${orchCmd}\n`)
|
|
78
|
+
chmodSync(launchFile, 0o755)
|
|
79
|
+
|
|
80
|
+
console.log('')
|
|
81
|
+
console.log(chalk.bold(' Shellmates — Pond'))
|
|
82
|
+
console.log(chalk.dim(' ─────────────────────────────────────'))
|
|
83
|
+
console.log(chalk.dim(' Orchestrator: ') + chalk.bold(orchestrator))
|
|
84
|
+
console.log(chalk.dim(' Agents: ') + chalk.bold(agents.join(', ')))
|
|
85
|
+
console.log(chalk.dim(' Project: ') + chalk.dim(project))
|
|
86
|
+
console.log(chalk.dim(' Session: ') + chalk.dim(sessionName))
|
|
87
|
+
console.log('')
|
|
88
|
+
console.log(chalk.dim(' Starting pond... attach with Ctrl+A (or configured prefix)'))
|
|
89
|
+
console.log('')
|
|
90
|
+
|
|
91
|
+
// Create detached tmux session
|
|
92
|
+
try {
|
|
93
|
+
execSync(`tmux new-session -d -s ${JSON.stringify(sessionName)} -x 220 -y 50`, { stdio: 'ignore' })
|
|
94
|
+
} catch {
|
|
95
|
+
console.log(chalk.red(` ✗ Could not create tmux session (already exists?)`))
|
|
96
|
+
console.log(chalk.dim(` Try: tmux attach -t ${sessionName}\n`))
|
|
97
|
+
process.exit(1)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Launch orchestrator
|
|
101
|
+
execSync(`tmux send-keys -t ${JSON.stringify(sessionName)} ${JSON.stringify(launchFile)} Enter`)
|
|
102
|
+
|
|
103
|
+
// Attach — this takes over the terminal
|
|
104
|
+
spawnSync('tmux', ['attach-session', '-t', sessionName], { stdio: 'inherit' })
|
|
105
|
+
}
|