ralph-cli-sandboxed 0.2.9 → 0.4.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 +99 -15
- package/dist/commands/action.d.ts +7 -0
- package/dist/commands/action.js +276 -0
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.js +701 -0
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +51 -0
- package/dist/commands/daemon.d.ts +23 -0
- package/dist/commands/daemon.js +422 -0
- package/dist/commands/docker.js +82 -4
- package/dist/commands/fix-config.d.ts +4 -0
- package/dist/commands/fix-config.js +388 -0
- package/dist/commands/help.js +80 -0
- package/dist/commands/init.js +135 -1
- package/dist/commands/listen.d.ts +8 -0
- package/dist/commands/listen.js +280 -0
- package/dist/commands/notify.d.ts +7 -0
- package/dist/commands/notify.js +165 -0
- package/dist/commands/once.js +8 -8
- package/dist/commands/prd.js +2 -2
- package/dist/commands/run.js +25 -12
- package/dist/config/languages.json +4 -0
- package/dist/index.js +14 -0
- package/dist/providers/telegram.d.ts +39 -0
- package/dist/providers/telegram.js +256 -0
- package/dist/templates/macos-scripts.d.ts +42 -0
- package/dist/templates/macos-scripts.js +448 -0
- package/dist/tui/ConfigEditor.d.ts +7 -0
- package/dist/tui/ConfigEditor.js +313 -0
- package/dist/tui/components/ArrayEditor.d.ts +22 -0
- package/dist/tui/components/ArrayEditor.js +193 -0
- package/dist/tui/components/BooleanToggle.d.ts +19 -0
- package/dist/tui/components/BooleanToggle.js +43 -0
- package/dist/tui/components/EditorPanel.d.ts +50 -0
- package/dist/tui/components/EditorPanel.js +232 -0
- package/dist/tui/components/HelpPanel.d.ts +13 -0
- package/dist/tui/components/HelpPanel.js +69 -0
- package/dist/tui/components/JsonSnippetEditor.d.ts +24 -0
- package/dist/tui/components/JsonSnippetEditor.js +380 -0
- package/dist/tui/components/KeyValueEditor.d.ts +34 -0
- package/dist/tui/components/KeyValueEditor.js +261 -0
- package/dist/tui/components/ObjectEditor.d.ts +23 -0
- package/dist/tui/components/ObjectEditor.js +227 -0
- package/dist/tui/components/PresetSelector.d.ts +23 -0
- package/dist/tui/components/PresetSelector.js +58 -0
- package/dist/tui/components/Preview.d.ts +18 -0
- package/dist/tui/components/Preview.js +190 -0
- package/dist/tui/components/ScrollableContainer.d.ts +38 -0
- package/dist/tui/components/ScrollableContainer.js +77 -0
- package/dist/tui/components/SectionNav.d.ts +31 -0
- package/dist/tui/components/SectionNav.js +130 -0
- package/dist/tui/components/StringEditor.d.ts +21 -0
- package/dist/tui/components/StringEditor.js +29 -0
- package/dist/tui/hooks/useConfig.d.ts +16 -0
- package/dist/tui/hooks/useConfig.js +89 -0
- package/dist/tui/hooks/useTerminalSize.d.ts +21 -0
- package/dist/tui/hooks/useTerminalSize.js +48 -0
- package/dist/tui/utils/presets.d.ts +52 -0
- package/dist/tui/utils/presets.js +191 -0
- package/dist/tui/utils/validation.d.ts +49 -0
- package/dist/tui/utils/validation.js +198 -0
- package/dist/utils/chat-client.d.ts +144 -0
- package/dist/utils/chat-client.js +102 -0
- package/dist/utils/config.d.ts +52 -0
- package/dist/utils/daemon-client.d.ts +36 -0
- package/dist/utils/daemon-client.js +70 -0
- package/dist/utils/message-queue.d.ts +58 -0
- package/dist/utils/message-queue.js +133 -0
- package/dist/utils/notification.d.ts +28 -1
- package/dist/utils/notification.js +146 -20
- package/docs/MACOS-DEVELOPMENT.md +435 -0
- package/docs/RALPH-SETUP-TEMPLATE.md +262 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -45,6 +45,8 @@ ralph docker run
|
|
|
45
45
|
| `ralph fix-prd [opts]` | Validate and recover corrupted PRD file |
|
|
46
46
|
| `ralph prompt [opts]` | Display resolved prompt |
|
|
47
47
|
| `ralph docker <sub>` | Manage Docker sandbox environment |
|
|
48
|
+
| `ralph daemon <sub>` | Manage host daemon for sandbox notifications |
|
|
49
|
+
| `ralph notify [msg]` | Send notification (from sandbox to host) |
|
|
48
50
|
| `ralph help` | Show help message |
|
|
49
51
|
|
|
50
52
|
> **Note:** `ralph prd <subcommand>` still works for compatibility (e.g., `ralph prd add`).
|
|
@@ -85,19 +87,51 @@ After running `ralph init`, you'll have:
|
|
|
85
87
|
|
|
86
88
|
### Notifications
|
|
87
89
|
|
|
88
|
-
Ralph can send notifications when events occur during automation. Configure
|
|
90
|
+
Ralph can send notifications when events occur during automation. Configure notifications in `.ralph/config.json`:
|
|
91
|
+
|
|
92
|
+
#### Using ntfy (Recommended)
|
|
93
|
+
|
|
94
|
+
[ntfy](https://ntfy.sh/) is a simple HTTP-based pub-sub notification service. Ralph uses curl to send notifications, so **no ntfy CLI installation is required**:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"notifications": {
|
|
99
|
+
"provider": "ntfy",
|
|
100
|
+
"ntfy": {
|
|
101
|
+
"topic": "my-ralph-notifications",
|
|
102
|
+
"server": "https://ntfy.sh"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| Field | Description |
|
|
109
|
+
|-------|-------------|
|
|
110
|
+
| `provider` | Set to `"ntfy"` for ntfy notifications |
|
|
111
|
+
| `ntfy.topic` | Your unique topic name (required) |
|
|
112
|
+
| `ntfy.server` | ntfy server URL (default: `https://ntfy.sh`) |
|
|
113
|
+
|
|
114
|
+
To receive notifications:
|
|
115
|
+
1. Subscribe to your topic on your phone ([ntfy app](https://ntfy.sh/)) or browser (`https://ntfy.sh/your-topic`)
|
|
116
|
+
2. Run `ralph docker run` - you'll get notifications on completion
|
|
117
|
+
|
|
118
|
+
#### Using a Custom Command
|
|
119
|
+
|
|
120
|
+
For other notification tools, use the `command` provider:
|
|
89
121
|
|
|
90
122
|
```json
|
|
91
123
|
{
|
|
92
|
-
"
|
|
124
|
+
"notifications": {
|
|
125
|
+
"provider": "command",
|
|
126
|
+
"command": "notify-send Ralph"
|
|
127
|
+
}
|
|
93
128
|
}
|
|
94
129
|
```
|
|
95
130
|
|
|
96
|
-
The message is appended as the last argument to your command. Supported
|
|
131
|
+
The message is appended as the last argument to your command. Supported tools include:
|
|
97
132
|
|
|
98
133
|
| Tool | Example Command | Description |
|
|
99
134
|
|------|----------------|-------------|
|
|
100
|
-
| [ntfy](https://ntfy.sh/) | `ntfy pub mytopic` | Push notifications to phone/desktop |
|
|
101
135
|
| notify-send (Linux) | `notify-send Ralph` | Desktop notifications on Linux |
|
|
102
136
|
| terminal-notifier (macOS) | `terminal-notifier -title Ralph -message` | Desktop notifications on macOS |
|
|
103
137
|
| Custom script | `/path/to/notify.sh` | Your own notification script |
|
|
@@ -113,25 +147,75 @@ Ralph sends notifications for these events:
|
|
|
113
147
|
| Run Stopped | "Ralph: Run stopped..." | `ralph run` stops due to no progress or max failures |
|
|
114
148
|
| Error | "Ralph: An error occurred." | CLI fails repeatedly |
|
|
115
149
|
|
|
116
|
-
####
|
|
150
|
+
#### Sandbox-to-Host Notifications (Daemon)
|
|
117
151
|
|
|
118
|
-
|
|
152
|
+
When running in a Docker sandbox, notifications are sent via the ralph daemon which runs on the host. The sandbox communicates with the daemon through a shared message file (`.ralph/messages.json`).
|
|
119
153
|
|
|
120
154
|
```bash
|
|
121
|
-
# 1
|
|
122
|
-
|
|
155
|
+
# Terminal 1: Start daemon on host
|
|
156
|
+
ralph daemon start
|
|
123
157
|
|
|
124
|
-
# 2
|
|
125
|
-
|
|
158
|
+
# Terminal 2: Run container
|
|
159
|
+
ralph docker run
|
|
160
|
+
|
|
161
|
+
# Inside container: Send notification manually
|
|
162
|
+
ralph notify "Hello from sandbox!"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The daemon watches for messages and executes the configured notification command on the host. This file-based approach works on all platforms (macOS, Linux, Windows) and allows other tools to integrate with the message queue.
|
|
126
166
|
|
|
127
|
-
|
|
128
|
-
|
|
167
|
+
#### Custom Daemon Actions
|
|
168
|
+
|
|
169
|
+
You can define custom actions that the sandbox can trigger. This example logs task completions and ralph finished events to a file:
|
|
170
|
+
|
|
171
|
+
```json
|
|
129
172
|
{
|
|
130
|
-
"
|
|
173
|
+
"daemon": {
|
|
174
|
+
"actions": {
|
|
175
|
+
"log_task": {
|
|
176
|
+
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') - Task completed:\" >> log.txt && echo",
|
|
177
|
+
"description": "Log task completion to file"
|
|
178
|
+
},
|
|
179
|
+
"log_complete": {
|
|
180
|
+
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') - Ralph finished: All PRD tasks complete\" >> log.txt",
|
|
181
|
+
"description": "Log ralph completion to file"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"events": {
|
|
185
|
+
"task_complete": [
|
|
186
|
+
{
|
|
187
|
+
"action": "log_task",
|
|
188
|
+
"message": "{{task}}"
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"ralph_complete": [
|
|
192
|
+
{
|
|
193
|
+
"action": "log_complete"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"action": "notify",
|
|
197
|
+
"message": "All tasks done!"
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
131
202
|
}
|
|
203
|
+
```
|
|
132
204
|
|
|
133
|
-
|
|
134
|
-
|
|
205
|
+
| Event | When Triggered |
|
|
206
|
+
|-------|----------------|
|
|
207
|
+
| `task_complete` | After each PRD task is marked as passing |
|
|
208
|
+
| `ralph_complete` | When all PRD tasks are complete |
|
|
209
|
+
| `iteration_complete` | After each `ralph once` iteration |
|
|
210
|
+
| `error` | When an error occurs |
|
|
211
|
+
|
|
212
|
+
The `{{task}}` placeholder is replaced with the task description. Events can trigger multiple actions - for example, `ralph_complete` above both logs to file and sends a notification.
|
|
213
|
+
|
|
214
|
+
Example `log.txt` output:
|
|
215
|
+
```
|
|
216
|
+
2024-01-15 14:23:01 - Task completed: Add user authentication
|
|
217
|
+
2024-01-15 14:45:32 - Task completed: Implement JWT tokens
|
|
218
|
+
2024-01-15 15:02:18 - Ralph finished: All PRD tasks complete
|
|
135
219
|
```
|
|
136
220
|
|
|
137
221
|
### Supported Languages
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute an action from config.json - works both inside and outside containers.
|
|
3
|
+
*
|
|
4
|
+
* Inside container: Uses file-based message queue to communicate with host daemon
|
|
5
|
+
* Outside container: Executes the command directly
|
|
6
|
+
*/
|
|
7
|
+
export declare function action(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { loadConfig, isRunningInContainer } from "../utils/config.js";
|
|
4
|
+
import { getMessagesPath, sendMessage, waitForResponse, } from "../utils/message-queue.js";
|
|
5
|
+
/**
|
|
6
|
+
* Execute an action from config.json - works both inside and outside containers.
|
|
7
|
+
*
|
|
8
|
+
* Inside container: Uses file-based message queue to communicate with host daemon
|
|
9
|
+
* Outside container: Executes the command directly
|
|
10
|
+
*/
|
|
11
|
+
export async function action(args) {
|
|
12
|
+
// Parse arguments
|
|
13
|
+
let actionName;
|
|
14
|
+
let actionArgs = [];
|
|
15
|
+
let debug = false;
|
|
16
|
+
let showList = false;
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if (arg === "--debug" || arg === "-d") {
|
|
20
|
+
debug = true;
|
|
21
|
+
}
|
|
22
|
+
else if (arg === "--help" || arg === "-h") {
|
|
23
|
+
showHelp();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
else if (arg === "--list" || arg === "-l") {
|
|
27
|
+
showList = true;
|
|
28
|
+
}
|
|
29
|
+
else if (!arg.startsWith("-")) {
|
|
30
|
+
if (!actionName) {
|
|
31
|
+
actionName = arg;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Collect remaining args as action arguments
|
|
35
|
+
actionArgs = args.slice(i);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Load config
|
|
41
|
+
let config;
|
|
42
|
+
try {
|
|
43
|
+
config = loadConfig();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
console.error("Failed to load config. Run 'ralph init' first.");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
// Get available actions from daemon config
|
|
50
|
+
const daemonActions = config.daemon?.actions || {};
|
|
51
|
+
const actionNames = Object.keys(daemonActions);
|
|
52
|
+
// If --list or no action specified, show available actions
|
|
53
|
+
if (showList || !actionName) {
|
|
54
|
+
if (actionNames.length === 0) {
|
|
55
|
+
console.log("No actions configured.");
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("Configure actions in .ralph/config.json:");
|
|
58
|
+
console.log(' {');
|
|
59
|
+
console.log(' "daemon": {');
|
|
60
|
+
console.log(' "actions": {');
|
|
61
|
+
console.log(' "build": {');
|
|
62
|
+
console.log(' "command": "./scripts/build.sh",');
|
|
63
|
+
console.log(' "description": "Build the project"');
|
|
64
|
+
console.log(' }');
|
|
65
|
+
console.log(' }');
|
|
66
|
+
console.log(' }');
|
|
67
|
+
console.log(' }');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log("Available actions:");
|
|
71
|
+
console.log("");
|
|
72
|
+
for (const [name, actionConfig] of Object.entries(daemonActions)) {
|
|
73
|
+
const desc = actionConfig.description || actionConfig.command;
|
|
74
|
+
console.log(` ${name.padEnd(20)} ${desc}`);
|
|
75
|
+
}
|
|
76
|
+
console.log("");
|
|
77
|
+
console.log("Run an action: ralph action <name> [args...]");
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Validate action exists
|
|
82
|
+
if (!daemonActions[actionName]) {
|
|
83
|
+
console.error(`Unknown action: ${actionName}`);
|
|
84
|
+
console.error("");
|
|
85
|
+
if (actionNames.length > 0) {
|
|
86
|
+
console.error(`Available actions: ${actionNames.join(", ")}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.error("No actions configured in .ralph/config.json");
|
|
90
|
+
}
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
const actionConfig = daemonActions[actionName];
|
|
94
|
+
const inContainer = isRunningInContainer();
|
|
95
|
+
if (debug) {
|
|
96
|
+
console.log(`[action] Name: ${actionName}`);
|
|
97
|
+
console.log(`[action] Args: ${actionArgs.join(" ") || "(none)"}`);
|
|
98
|
+
console.log(`[action] Command: ${actionConfig.command}`);
|
|
99
|
+
console.log(`[action] In container: ${inContainer}`);
|
|
100
|
+
}
|
|
101
|
+
if (inContainer) {
|
|
102
|
+
// Inside container - use file-based message queue to execute on host
|
|
103
|
+
await executeViaQueue(actionName, actionArgs, debug);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Outside container - execute directly
|
|
107
|
+
await executeDirectly(actionConfig.command, actionArgs, debug);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Execute action via message queue (when running inside container).
|
|
112
|
+
*/
|
|
113
|
+
async function executeViaQueue(actionName, args, debug) {
|
|
114
|
+
const messagesPath = getMessagesPath(true);
|
|
115
|
+
if (!existsSync(messagesPath)) {
|
|
116
|
+
const ralphDir = "/workspace/.ralph";
|
|
117
|
+
if (!existsSync(ralphDir)) {
|
|
118
|
+
console.error("Error: .ralph directory not mounted in container.");
|
|
119
|
+
console.error("Make sure the container is started with 'ralph docker run'.");
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Send message via file queue
|
|
124
|
+
const messageId = sendMessage(messagesPath, "sandbox", actionName, args.length > 0 ? args : undefined);
|
|
125
|
+
if (debug) {
|
|
126
|
+
console.log(`[action] Sent message: ${messageId}`);
|
|
127
|
+
}
|
|
128
|
+
console.log(`Executing action: ${actionName}`);
|
|
129
|
+
console.log("Waiting for daemon response...");
|
|
130
|
+
// Wait for response with longer timeout for actions that may take time
|
|
131
|
+
const response = await waitForResponse(messagesPath, messageId, 60000);
|
|
132
|
+
if (!response) {
|
|
133
|
+
console.error("No response from daemon (timeout).");
|
|
134
|
+
console.error("");
|
|
135
|
+
console.error("Make sure the daemon is running on the host:");
|
|
136
|
+
console.error(" ralph daemon start");
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
if (debug) {
|
|
140
|
+
console.log(`[action] Response: ${JSON.stringify(response)}`);
|
|
141
|
+
}
|
|
142
|
+
// Display output
|
|
143
|
+
if (response.output) {
|
|
144
|
+
console.log("");
|
|
145
|
+
console.log(response.output);
|
|
146
|
+
}
|
|
147
|
+
if (response.success) {
|
|
148
|
+
console.log("");
|
|
149
|
+
console.log(`Action '${actionName}' completed successfully.`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.error("");
|
|
153
|
+
console.error(`Action '${actionName}' failed: ${response.error || "Unknown error"}`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Execute action directly on host (when running outside container).
|
|
159
|
+
*/
|
|
160
|
+
async function executeDirectly(command, args, debug) {
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
// Build full command with arguments
|
|
163
|
+
let fullCommand = command;
|
|
164
|
+
if (args.length > 0) {
|
|
165
|
+
fullCommand = `${command} ${args.map(a => `"${a.replace(/"/g, '\\"')}"`).join(" ")}`;
|
|
166
|
+
}
|
|
167
|
+
if (debug) {
|
|
168
|
+
console.log(`[action] Executing: ${fullCommand}`);
|
|
169
|
+
}
|
|
170
|
+
console.log(`Executing: ${fullCommand}`);
|
|
171
|
+
console.log("");
|
|
172
|
+
const proc = spawn(fullCommand, [], {
|
|
173
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
174
|
+
shell: true,
|
|
175
|
+
cwd: process.cwd(),
|
|
176
|
+
});
|
|
177
|
+
// Stream stdout in real-time
|
|
178
|
+
proc.stdout.on("data", (data) => {
|
|
179
|
+
process.stdout.write(data);
|
|
180
|
+
});
|
|
181
|
+
// Stream stderr in real-time
|
|
182
|
+
proc.stderr.on("data", (data) => {
|
|
183
|
+
process.stderr.write(data);
|
|
184
|
+
});
|
|
185
|
+
proc.on("close", (code) => {
|
|
186
|
+
if (code === 0) {
|
|
187
|
+
console.log("");
|
|
188
|
+
console.log("Action completed successfully.");
|
|
189
|
+
resolve();
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.error("");
|
|
193
|
+
console.error(`Action failed with exit code: ${code}`);
|
|
194
|
+
process.exit(code || 1);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
proc.on("error", (err) => {
|
|
198
|
+
console.error(`Failed to execute action: ${err.message}`);
|
|
199
|
+
reject(err);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function showHelp() {
|
|
204
|
+
console.log(`
|
|
205
|
+
ralph action - Execute host actions from config.json
|
|
206
|
+
|
|
207
|
+
USAGE:
|
|
208
|
+
ralph action [name] [args...] Execute an action
|
|
209
|
+
ralph action --list List available actions
|
|
210
|
+
ralph action --help Show this help
|
|
211
|
+
|
|
212
|
+
OPTIONS:
|
|
213
|
+
-l, --list List all configured actions
|
|
214
|
+
-d, --debug Show debug output
|
|
215
|
+
-h, --help Show this help message
|
|
216
|
+
|
|
217
|
+
DESCRIPTION:
|
|
218
|
+
This command executes actions defined in the daemon.actions section of
|
|
219
|
+
.ralph/config.json. When running inside a container, the action is
|
|
220
|
+
executed on the host via the daemon. When running on the host directly,
|
|
221
|
+
the action is executed locally.
|
|
222
|
+
|
|
223
|
+
Actions are useful for triggering host operations like:
|
|
224
|
+
- Building Xcode projects (requires host Xcode installation)
|
|
225
|
+
- Running deployment scripts
|
|
226
|
+
- Executing platform-specific tools not available in the container
|
|
227
|
+
|
|
228
|
+
CONFIGURATION:
|
|
229
|
+
Define actions in .ralph/config.json:
|
|
230
|
+
|
|
231
|
+
{
|
|
232
|
+
"daemon": {
|
|
233
|
+
"actions": {
|
|
234
|
+
"build": {
|
|
235
|
+
"command": "./scripts/build.sh",
|
|
236
|
+
"description": "Build the project"
|
|
237
|
+
},
|
|
238
|
+
"deploy": {
|
|
239
|
+
"command": "./scripts/deploy.sh --env staging",
|
|
240
|
+
"description": "Deploy to staging"
|
|
241
|
+
},
|
|
242
|
+
"gen_xcode": {
|
|
243
|
+
"command": "swift package generate-xcodeproj",
|
|
244
|
+
"description": "Generate Xcode project from Swift package"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
EXAMPLES:
|
|
251
|
+
# List available actions
|
|
252
|
+
ralph action --list
|
|
253
|
+
ralph action
|
|
254
|
+
|
|
255
|
+
# Execute an action
|
|
256
|
+
ralph action build
|
|
257
|
+
ralph action deploy --env production
|
|
258
|
+
ralph action gen_xcode
|
|
259
|
+
|
|
260
|
+
# Execute with arguments
|
|
261
|
+
ralph action build --release
|
|
262
|
+
ralph action deploy staging
|
|
263
|
+
|
|
264
|
+
SETUP FOR CONTAINER USAGE:
|
|
265
|
+
1. Define actions in .ralph/config.json
|
|
266
|
+
2. Start the daemon on the host: ralph daemon start
|
|
267
|
+
3. Run the container: ralph docker run
|
|
268
|
+
4. From inside the container: ralph action build
|
|
269
|
+
|
|
270
|
+
NOTES:
|
|
271
|
+
- Actions configured in daemon.actions are automatically available to the daemon
|
|
272
|
+
- When in a container, the daemon must be running to process action requests
|
|
273
|
+
- Actions have a 60-second timeout when executed via the daemon
|
|
274
|
+
- Output is streamed in real-time when executing directly on host
|
|
275
|
+
`);
|
|
276
|
+
}
|