Skip to content

Commit b9d768b

Browse files
committed
update adding claude.md
1 parent 54ad0c9 commit b9d768b

11 files changed

Lines changed: 1169 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+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
name: find-skills
3+
description: Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.
4+
---
5+
6+
# Find Skills
7+
8+
Search the public skill registry for community-contributed skills
9+
relevant to the user's current task and install them into this project.
10+
11+
## Instructions
12+
13+
1. Identify the key technologies, frameworks, or task types from the
14+
user's request that might have community skills available
15+
2. Ask the user: "Would you like me to search for community skills
16+
for [identified technologies]?"
17+
3. If the user agrees, run:
18+
```bash
19+
caliber skills --query "<relevant terms>"
20+
```
21+
This outputs the top 5 matching skills with scores and descriptions.
22+
4. Present the results to the user and ask which ones to install
23+
5. Install the selected skills:
24+
```bash
25+
caliber skills --install <slug1>,<slug2>
26+
```
27+
6. Read the installed SKILL.md files to load them into your current
28+
context so you can use them immediately in this session
29+
7. Summarize what was installed and continue with the user's task
30+
31+
## Examples
32+
33+
User: "let's build a web app using React"
34+
-> "I notice you want to work with React. Would you like me to search
35+
for community skills that could help with React development?"
36+
-> If yes: run `caliber skills --query "react frontend"`
37+
-> Show the user the results, ask which to install
38+
-> Run `caliber skills --install <selected-slugs>`
39+
-> Read the installed files and continue
40+
41+
User: "help me set up Docker for this project"
42+
-> "Would you like me to search for Docker-related skills?"
43+
-> If yes: run `caliber skills --query "docker deployment"`
44+
45+
User: "I need to write tests for this Python ML pipeline"
46+
-> "Would you like me to find skills for Python ML testing?"
47+
-> If yes: run `caliber skills --query "python machine-learning testing"`
48+
49+
## When NOT to trigger
50+
51+
- The user is working within an already well-configured area
52+
- You already suggested skills for this technology in this session
53+
- The user is in the middle of urgent debugging or time-sensitive work
54+
- The technology is too generic (e.g. just "code" or "programming")
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
name: license-function
3+
description: Adds a new procedural license function to src/cpanel.inc.php following the existing pattern: create Cpanel instance, make API call, log with request_log and myadmin_log, return result. Use when user says 'add license function', 'new cpanel function', 'add API wrapper'. Do NOT use for Plugin.php class methods.
4+
---
5+
# License Function
6+
7+
Add a new procedural license function to `src/cpanel.inc.php` following the established patterns in this cPanel licensing plugin.
8+
9+
## Critical
10+
11+
- All functions go in `src/cpanel.inc.php` — NEVER in `src/Plugin.php` (that file is for event handlers only).
12+
- Every function that calls the cPanel API MUST log via `request_log()` with the exact 7-argument signature used in existing code.
13+
- Always instantiate `\Detain\Cpanel\Cpanel` with the constants `CPANEL_LICENSING_USERNAME` and `CPANEL_LICENSING_PASSWORD` — never hardcode or pass credentials.
14+
- If the function accepts an IP address, validate it with `validIp($ipAddress, false)` before making any API call, returning `false` on invalid input.
15+
- The module is always `'licenses'` — use `$module = 'licenses';` or the string literal directly.
16+
- After adding the function, register it in `Plugin.php``getRequirements()` so the lazy-loader can find it.
17+
18+
## Instructions
19+
20+
1. **Read existing functions in `src/cpanel.inc.php`** to confirm the current patterns and avoid name collisions. Every function in this file follows a naming convention: `{action}_cpanel` or `get_cpanel_{thing}`. Name your function to match.
21+
- Verify: your function name does not already exist in the file.
22+
23+
2. **Write the PHPDoc block** above the function. Follow the existing format:
24+
```php
25+
/**
26+
* function_name()
27+
* brief description of what it does
28+
*
29+
* @param type $paramName description
30+
* @return type description
31+
*/
32+
```
33+
- Verify: the `@param` and `@return` types match actual usage.
34+
35+
3. **Write the function body** using this exact skeleton (derived from `activate_cpanel`, `verify_cpanel`, `get_cpanel_license_data_by_ip`):
36+
37+
```php
38+
function your_function_name($ipAddress)
39+
{
40+
// Step A: (If IP-based) Validate input
41+
if (!validIp($ipAddress, false)) {
42+
return false;
43+
}
44+
45+
// Step B: Instantiate the cPanel API client
46+
$cpl = new \Detain\Cpanel\Cpanel(CPANEL_LICENSING_USERNAME, CPANEL_LICENSING_PASSWORD);
47+
48+
// Step C: Build the request array
49+
$request = ['ip' => $ipAddress];
50+
51+
// Step D: Call the appropriate API method
52+
$response = $cpl->apiMethodName($request);
53+
54+
// Step E: Log the API call with request_log
55+
request_log('licenses', false, __FUNCTION__, 'cpanel', 'apiMethodName', $request, $response);
56+
57+
// Step F: (Optional) Log additional info with myadmin_log
58+
myadmin_log('licenses', 'info', json_encode($response), __LINE__, __FILE__);
59+
60+
// Step G: Process and return the result
61+
return $response;
62+
}
63+
```
64+
65+
Key details for each step:
66+
- **Step A**: Only needed for IP-based functions. Use `validIp($ipAddress, false)` — the `false` second arg disables IPv6-only check.
67+
- **Step B**: Always use `\Detain\Cpanel\Cpanel` with the two constant args. Never `use` import it at file level (this is a procedural file with no namespace).
68+
- **Step C**: Build request as associative array. Keys match cPanel Manage2 API parameters.
69+
- **Step E**: `request_log` signature: `request_log($module, $accountId, $functionName, $provider, $apiMethod, $request, $response)`. Use `$GLOBALS['tf']->session->account_id` for the account ID when the function runs in an authenticated user context, or `false` when it runs in admin/background context.
70+
- **Step F**: Use `myadmin_log('licenses', $level, $message, __LINE__, __FILE__)` — level is typically `'info'` or `'error'`.
71+
72+
- Verify: the function uses `\Detain\Cpanel\Cpanel` (not `Cpanel` unqualified), calls `request_log` with all 7 args, and returns a value.
73+
74+
4. **Register the function in `src/Plugin.php``getRequirements()`**. Add a line using the same path pattern as existing entries:
75+
76+
```php
77+
$loader->add_requirement('your_function_name', '/../vendor/detain/myadmin-cpanel-licensing/src/cpanel.inc.php');
78+
```
79+
80+
Use `add_requirement` for functions callable from other modules. Use `add_page_requirement` for functions that render pages or are only used in web context.
81+
82+
- Verify: the string passed to `add_requirement` exactly matches the function name.
83+
84+
5. **Run lint and tests**:
85+
```bash
86+
php -l src/cpanel.inc.php
87+
php -l src/Plugin.php
88+
vendor/bin/phpunit
89+
```
90+
- Verify: no syntax errors and all tests pass.
91+
92+
## Examples
93+
94+
### User says: "Add a function to change the package of a cPanel license by IP"
95+
96+
**Actions taken:**
97+
98+
1. Read `src/cpanel.inc.php` to confirm no `change_cpanel_package` function exists.
99+
2. Add the function at the end of `src/cpanel.inc.php` (before the closing `?>` if present, or at end of file):
100+
101+
```php
102+
/**
103+
* change_cpanel_package()
104+
* changes the package on an existing cpanel license
105+
*
106+
* @param string $ipAddress ip address of the license
107+
* @param integer $packageId the new package id
108+
* @return array|bool the response attributes or false on failure
109+
*/
110+
function change_cpanel_package($ipAddress, $packageId)
111+
{
112+
if (!validIp($ipAddress, false)) {
113+
return false;
114+
}
115+
$packageId = (int) $packageId;
116+
$cpl = new \Detain\Cpanel\Cpanel(CPANEL_LICENSING_USERNAME, CPANEL_LICENSING_PASSWORD);
117+
$request = ['ip' => $ipAddress, 'packageid' => $packageId];
118+
$response = $cpl->changePackage($request);
119+
request_log('licenses', false, __FUNCTION__, 'cpanel', 'changePackage', $request, $response);
120+
myadmin_log('licenses', 'info', "change_cpanel_package({$ipAddress}, {$packageId}) returned " . json_encode($response['attr']), __LINE__, __FILE__);
121+
if (isset($response['attr']['reason']) && $response['attr']['reason'] == 'OK') {
122+
return $response['attr'];
123+
}
124+
return false;
125+
}
126+
```
127+
128+
3. Register in `src/Plugin.php``getRequirements()`:
129+
```php
130+
$loader->add_requirement('change_cpanel_package', '/../vendor/detain/myadmin-cpanel-licensing/src/cpanel.inc.php');
131+
```
132+
133+
4. Run `php -l src/cpanel.inc.php && php -l src/Plugin.php && vendor/bin/phpunit`.
134+
135+
**Result:** New function follows exact project patterns — procedural, uses constants for auth, logs both via `request_log` and `myadmin_log`, validates IP input, casts integer params.
136+
137+
## Common Issues
138+
139+
- **`Fatal error: Class 'Detain\Cpanel\Cpanel' not found`**: The `detain/cpanel-licensing` package is not installed. Run `composer install` or `composer require detain/cpanel-licensing:dev-master`.
140+
141+
- **`Call to undefined function request_log()`**: This function is defined in the main MyAdmin framework, not in this plugin. The function is only available when running within the full MyAdmin application context. Tests in this plugin use reflection/static analysis and do NOT bootstrap the framework — do not expect `request_log` to be callable in unit tests.
142+
143+
- **`Call to undefined function validIp()`**: Same as above — `validIp()` is from `include/validations.php` in the main MyAdmin repo. Available at runtime but not in isolated plugin tests.
144+
145+
- **`Undefined constant CPANEL_LICENSING_USERNAME`**: The constants are set via the settings system at runtime. For CLI scripts in `bin/`, ensure you include the appropriate bootstrap. For tests, mock or skip — existing tests use static file analysis to avoid needing these constants.
146+
147+
- **Function not found at runtime after adding it**: You forgot to register it in `Plugin.php``getRequirements()`. The MyAdmin lazy-loader only knows about functions listed there. Also verify the `function_requirements('your_function_name')` call is made before invoking your function from Plugin event handlers.
148+
149+
- **`request_log` second argument confusion**: Use `$GLOBALS['tf']->session->account_id` when the function is called during an authenticated user action (like `activate_cpanel` does). Use `false` when running in admin/background/CLI context (like `deactivate_cpanel`, `verify_cpanel` do).
150+
151+
- **Tests fail after adding function**: The `SourceFileAnalysisTest.php` reads `src/` files via `file_get_contents` and checks for patterns. If your function has syntax errors or doesn't follow conventions, it may trigger test failures. Run `php -l src/cpanel.inc.php` first to catch syntax issues.

0 commit comments

Comments
 (0)