Skip to content

Commit 5d75aaa

Browse files
committed
update adding claude.md
1 parent fb1377b commit 5d75aaa

11 files changed

Lines changed: 1271 additions & 47 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
if grep -q "caliber" .git/hooks/pre-commit 2>/dev/null; then
3+
exit 0
4+
fi
5+
FLAG="/tmp/caliber-nudge-$(echo "$PWD" | shasum | cut -c1-8)"
6+
find /tmp -maxdepth 1 -name "caliber-nudge-*" -mmin +120 -delete 2>/dev/null
7+
if [ -f "$FLAG" ]; then
8+
exit 0
9+
fi
10+
touch "$FLAG"
11+
printf '{"decision":"block","reason":"Caliber agent config sync is not set up on this machine. Tell the user: This project uses Caliber to keep agent configs in sync — it is not set up yet. Want me to run /setup-caliber? (~30 seconds)"}'

.claude/settings.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"hooks": {
3+
"Stop": [
4+
{
5+
"matcher": "",
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": ".claude/hooks/caliber-check-sync.sh",
10+
"description": "Caliber: offer setup if not configured"
11+
}
12+
]
13+
}
14+
],
15+
"PostToolUse": [
16+
{
17+
"matcher": "",
18+
"hooks": [
19+
{
20+
"type": "command",
21+
"command": "caliber learn observe",
22+
"description": "Caliber: recording tool usage for session learning"
23+
}
24+
]
25+
}
26+
],
27+
"PostToolUseFailure": [
28+
{
29+
"matcher": "",
30+
"hooks": [
31+
{
32+
"type": "command",
33+
"command": "caliber learn observe --failure",
34+
"description": "Caliber: recording tool failure for session learning"
35+
}
36+
]
37+
}
38+
],
39+
"UserPromptSubmit": [
40+
{
41+
"matcher": "",
42+
"hooks": [
43+
{
44+
"type": "command",
45+
"command": "caliber learn observe --prompt",
46+
"description": "Caliber: recording user prompt for correction detection"
47+
}
48+
]
49+
}
50+
],
51+
"SessionEnd": [
52+
{
53+
"matcher": "",
54+
"hooks": [
55+
{
56+
"type": "command",
57+
"command": "caliber learn finalize --auto",
58+
"description": "Caliber: finalizing session learnings"
59+
}
60+
]
61+
},
62+
{
63+
"matcher": "",
64+
"hooks": [
65+
{
66+
"type": "command",
67+
"command": "caliber refresh --quiet",
68+
"description": "Caliber: auto-refreshing docs based on code changes"
69+
}
70+
]
71+
}
72+
]
73+
},
74+
"permissions": {
75+
"allow": [
76+
"Bash(git *)"
77+
]
78+
}
79+
}

.claude/skills/bin-script/SKILL.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
---
2+
name: bin-script
3+
description: Creates a new CLI script in bin/ for DirectAdmin API operations. Use when user says 'add bin script', 'create CLI tool', 'new admin script', or needs a standalone operational script like bin/add_user.php or bin/suspend_user.php. Covers autoload require, HTTPSocket setup, SSL connect, arg parsing, and result printing. Do NOT use for src/ class code or Plugin.php event handlers.
4+
---
5+
# bin-script
6+
7+
## Critical
8+
9+
- All scripts live in `bin/` — never `src/`.
10+
- Always use `use Detain\MyAdminDirectAdminWeb\HTTPSocket;` with the autoloader — never include the HTTPSocket source file directly (that is legacy, see `bin/add_domain.php`).
11+
- Port is always `2222` — never 80, 443, or 8080.
12+
- SSL: use the ssl scheme prefix when `$server_ssl == 'Y'`; otherwise connect bare host. Never use the http scheme prefix in new scripts.
13+
- Use `fetch_parsed_body()` for structured results; use `fetch_body()` only when you need raw string output.
14+
- Check `$result['error'] != "0"` for API errors; error detail is in `$result['text']` and `$result['details']`.
15+
- Never interpolate raw `$_GET`/`$_POST` into queries — these are CLI scripts; use `$_SERVER['argv']` for input.
16+
17+
## Instructions
18+
19+
### 1. Choose the bootstrap style
20+
21+
Two patterns exist. Pick one based on whether the script needs live DB server credentials:
22+
23+
**A — Hardcoded / dev credentials** (like `bin/add_user.php`, `bin/suspend_user.php`):
24+
```php
25+
require_once('../vendor/autoload.php');
26+
```
27+
Used for quick standalone scripts where credentials are set directly in the file.
28+
29+
**B — MyAdmin DB lookup** (like `bin/show_all_users.php`, `bin/server_information.php`):
30+
```php
31+
include_once __DIR__.'/../../../../include/functions.inc.php';
32+
```
33+
Used when the script must look up a real server from `website_masters`. Requires running inside a MyAdmin checkout.
34+
35+
Verify your chosen autoload path resolves before writing the rest of the script.
36+
37+
### 2. Write the file header
38+
39+
```php
40+
<?php
41+
42+
use Detain\MyAdminDirectAdminWeb\HTTPSocket;
43+
44+
// Step 1 bootstrap here (require_once or include_once)
45+
```
46+
47+
### 3. Set server connection variables
48+
49+
For pattern A:
50+
```php
51+
$server_login = 'admin';
52+
$server_pass = 'admin_password';
53+
$server_host = 'da1.is.cc'; // where the API connects to
54+
$server_ssl = 'Y';
55+
$server_port = 2222;
56+
```
57+
58+
For pattern B (DB lookup):
59+
```php
60+
$db = get_module_db('webhosting');
61+
if (count($_SERVER['argv']) < 2) {
62+
die("Call like {$_SERVER['argv'][0]} <hostname>\nwhere <hostname> is a webhosting server such as webhosting2004.interserver.net");
63+
}
64+
$db->query("select * from website_masters where website_name='".$db->real_escape($_SERVER['argv'][1])."'", __LINE__, __FILE__);
65+
if ($db->num_rows() == 0) {
66+
die("Invalid Server {$_SERVER['argv'][1]} passed, did not match any webhosting server name");
67+
}
68+
$db->next_record(MYSQL_ASSOC);
69+
$server_name = $db->Record['website_ip'];
70+
$server_port = 2222;
71+
$password = $db->Record['website_key'];
72+
```
73+
74+
### 4. Connect HTTPSocket
75+
76+
For pattern A:
77+
```php
78+
$sock = new HTTPSocket();
79+
if ($server_ssl == 'Y') {
80+
$sock->connect('ssl://'.$server_host, $server_port);
81+
} else {
82+
$sock->connect($server_host, $server_port);
83+
}
84+
$sock->set_login($server_login, $server_pass);
85+
```
86+
87+
For pattern B:
88+
```php
89+
$sock = new HTTPSocket();
90+
$sock->connect('ssl://'.$server_name, $server_port);
91+
$sock->set_login('admin', $password);
92+
```
93+
94+
For POST requests, add `$sock->set_method('POST');` immediately after `set_login()`.
95+
96+
For admin impersonation: `$sock->set_login('admin|'.$username, $adminPass);`
97+
98+
Verify `HTTPSocket` is importable: run `vendor/bin/phpunit tests/HTTPSocketTest.php`.
99+
100+
### 5. Issue the DirectAdmin API query
101+
102+
GET (no payload — pass params as array):
103+
```php
104+
$sock->query('/CMD_API_ENDPOINT', ['param' => $value]);
105+
```
106+
107+
POST (with payload array):
108+
```php
109+
$sock->query(
110+
'/CMD_API_ENDPOINT',
111+
[
112+
'action' => 'create',
113+
'key' => $value,
114+
]
115+
);
116+
```
117+
118+
Common endpoints and their required fields:
119+
120+
| Action | Endpoint | Key fields |
121+
|---|---|---|
122+
| Create user | `/CMD_API_ACCOUNT_USER` | `action=create`, `username`, `email`, `passwd`, `passwd2`, `domain`, `package`, `ip` |
123+
| Suspend user | `/CMD_API_SELECT_USERS` | `location=CMD_SELECT_USERS`, `suspend=Suspend`, `select0=$username` |
124+
| Unsuspend user | `/CMD_API_SELECT_USERS` | `location=CMD_SELECT_USERS`, `suspend=Unsuspend`, `select0=$username` |
125+
| Delete user | `/CMD_API_SELECT_USERS` | `confirmed=Confirm`, `delete=yes`, `select0=$username` |
126+
| Show user config | `/CMD_API_SHOW_USER_CONFIG` | `user=$username` |
127+
| All users | `/CMD_API_SHOW_ALL_USERS` ||
128+
| Server stats | `/CMD_API_ADMIN_STATS` ||
129+
130+
### 6. Fetch and print the result
131+
132+
```php
133+
$result = $sock->fetch_parsed_body(); // array via parse_str
134+
print_r($result);
135+
136+
if ($result['error'] != '0') {
137+
echo "<b>Error: <br>\n";
138+
echo $result['text']."<br>\n";
139+
echo $result['details']."<br></b>\n";
140+
} else {
141+
echo "Success<br>\n";
142+
}
143+
144+
exit(0);
145+
```
146+
147+
Omit the error-check block for read-only/info queries that don't return an `error` key (e.g. `CMD_API_SHOW_ALL_USERS` returns a list).
148+
149+
## Examples
150+
151+
**User says:** "Add a bin script to add a subdomain for a user"
152+
153+
**Actions taken:**
154+
1. Pattern A chosen (dev/standalone, no DB needed).
155+
2. File created at `bin/add_subdomain.php`.
156+
3. Credentials set as variables; SSL connect to port 2222.
157+
4. `set_method('POST')` added because this is a write operation.
158+
5. Query to `/CMD_API_SUBDOMAINS` with `action=create`.
159+
6. `fetch_parsed_body()` called, error checked.
160+
161+
**Result:**
162+
```php
163+
<?php
164+
165+
use Detain\MyAdminDirectAdminWeb\HTTPSocket;
166+
167+
require_once('../vendor/autoload.php');
168+
169+
$server_login = 'admin';
170+
$server_pass = 'admin_password';
171+
$server_host = 'da1.is.cc'; // where the API connects to
172+
$server_ssl = 'Y';
173+
$server_port = 2222;
174+
175+
$username = 'targetuser';
176+
$subdomain = 'sub';
177+
$domain = 'example.com';
178+
179+
$sock = new HTTPSocket();
180+
if ($server_ssl == 'Y') {
181+
$sock->connect('ssl://'.$server_host, $server_port);
182+
} else {
183+
$sock->connect($server_host, $server_port);
184+
}
185+
$sock->set_login('admin|'.$username, $server_pass);
186+
$sock->set_method('POST');
187+
188+
$sock->query(
189+
'/CMD_API_SUBDOMAINS',
190+
[
191+
'action' => 'create',
192+
'domain' => $domain,
193+
'subdomain' => $subdomain,
194+
]
195+
);
196+
197+
$result = $sock->fetch_parsed_body();
198+
print_r($result);
199+
200+
if ($result['error'] != '0') {
201+
echo "<b>Error creating subdomain {$subdomain}.{$domain}:<br>\n";
202+
echo $result['text']."<br>\n";
203+
echo $result['details']."<br></b>\n";
204+
} else {
205+
echo "Subdomain {$subdomain}.{$domain} created<br>\n";
206+
}
207+
208+
exit(0);
209+
```
210+
211+
## Common Issues
212+
213+
**`Class 'Detain\MyAdminDirectAdminWeb\HTTPSocket' not found`**
214+
- You used a direct include of the HTTPSocket source file instead of the autoloader.
215+
- Fix: use `require_once('../vendor/autoload.php');` and add `use Detain\MyAdminDirectAdminWeb\HTTPSocket;` at top.
216+
- Verify: `vendor/bin/phpunit tests/HTTPSocketTest.php` must pass.
217+
218+
**`$result['error']` is undefined / `print_r` shows empty array**
219+
- You called `fetch_parsed_body()` on an endpoint that returns raw text (e.g. `CMD_API_SHOW_ALL_USERS` returns a list).
220+
- Fix: switch to `fetch_body()` and parse manually, or check DirectAdmin docs for that endpoint's response format.
221+
222+
**`Connection refused` or SSL handshake failure**
223+
- Port 2222 must be open on the target server.
224+
- The ssl scheme prefix is required when `$server_ssl == 'Y'` — omitting it causes a plaintext-on-TLS mismatch.
225+
- Fix: confirm with `openssl s_client -connect da1.is.cc:2222`.
226+
227+
**Pattern B: `Invalid Server ... passed, did not match any webhosting server name`**
228+
- The `$_SERVER['argv'][1]` value doesn't match a `website_name` in `website_masters`.
229+
- Fix: check valid hostnames with `SELECT website_name FROM website_masters LIMIT 10;`.
230+
231+
**Script works locally but `include_once __DIR__.'/../../../..'` fails in another checkout depth**
232+
- Pattern B hard-codes four levels up to the MyAdmin root.
233+
- Fix: use pattern A with hardcoded credentials for portable standalone scripts, or adjust the relative path to match your checkout structure.

0 commit comments

Comments
 (0)