@lifeaitools/rdc-skills 0.9.5 → 0.9.7
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.
|
@@ -31,4 +31,4 @@ jobs:
|
|
|
31
31
|
STATUS="${{ job.status }}"
|
|
32
32
|
curl -s -X POST "${{ secrets.CLAUTH_CHANNEL_URL }}" \
|
|
33
33
|
-H "Content-Type: application/json" \
|
|
34
|
-
-d "{\"
|
|
34
|
+
-d "{\"event\":\"npm-publish\",\"package\":\"rdc-skills\",\"version\":\"${VERSION}\",\"status\":\"${STATUS}\",\"source\":\"github-actions\"}"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifeaitools/rdc-skills",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "RDC typed-agent dispatch skill suite for Claude Code
|
|
3
|
+
"version": "0.9.7",
|
|
4
|
+
"description": "RDC typed-agent dispatch skill suite for Claude Code \u00e2\u20ac\u201d plan, build, review, overnight builds",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
7
7
|
"claude-code-plugin",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "plugin",
|
|
20
20
|
"skills": "skills/",
|
|
21
21
|
"guides": "guides/",
|
|
22
|
-
"version": "0.9.
|
|
22
|
+
"version": "0.9.6",
|
|
23
23
|
"commands": "commands/"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
@@ -120,6 +120,63 @@ function buildPluginCache(cacheDir, version, gitSha) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// ── User-skills cleanup ───────────────────────────────────────────────────────
|
|
124
|
+
// Older installer versions wrote skill files directly to ~/.claude/skills/user/.
|
|
125
|
+
// Claude Code loads that directory AND the plugin cache, so any rdc skills left
|
|
126
|
+
// there produce duplicate registrations and break the resolver.
|
|
127
|
+
// This function nukes any entry whose frontmatter name starts with "rdc:".
|
|
128
|
+
function cleanUserSkills(userSkillsDir) {
|
|
129
|
+
if (!fs.existsSync(userSkillsDir)) return 0;
|
|
130
|
+
let removed = 0;
|
|
131
|
+
for (const entry of fs.readdirSync(userSkillsDir, { withFileTypes: true })) {
|
|
132
|
+
const candidate = path.join(userSkillsDir, entry.name);
|
|
133
|
+
let skillFile = null;
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
// New format: <name>/SKILL.md or <name>/skill.md
|
|
136
|
+
for (const sf of ['SKILL.md', 'skill.md']) {
|
|
137
|
+
const p = path.join(candidate, sf);
|
|
138
|
+
if (fs.existsSync(p)) { skillFile = p; break; }
|
|
139
|
+
}
|
|
140
|
+
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'skill.md' && entry.name !== 'SKILL.md' && entry.name !== 'README.md') {
|
|
141
|
+
// Old format: rdc-deploy.md flat file
|
|
142
|
+
skillFile = candidate;
|
|
143
|
+
}
|
|
144
|
+
if (!skillFile) continue;
|
|
145
|
+
const fm = readFrontmatter(skillFile);
|
|
146
|
+
if (fm.name && fm.name.startsWith('rdc:')) {
|
|
147
|
+
try {
|
|
148
|
+
if (entry.isDirectory()) fs.rmSync(candidate, { recursive: true, force: true });
|
|
149
|
+
else fs.unlinkSync(candidate);
|
|
150
|
+
removed++;
|
|
151
|
+
} catch {}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return removed;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Stale hook cleanup ────────────────────────────────────────────────────────
|
|
158
|
+
// Remove hook files from ~/.claude/hooks/ that are no longer in the source hooks/ dir.
|
|
159
|
+
// Prevents orphaned hooks (removed from source but still installed) from misfiring.
|
|
160
|
+
function cleanStaleHooks(hooksDstDir, hooksSrcDir) {
|
|
161
|
+
if (!fs.existsSync(hooksDstDir) || !fs.existsSync(hooksSrcDir)) return 0;
|
|
162
|
+
const sourceFiles = new Set(fs.readdirSync(hooksSrcDir).filter(f => f.endsWith('.js')));
|
|
163
|
+
// These hooks were written by us (rdc-skills) — safe to remove if no longer in source.
|
|
164
|
+
// We only manage our own hooks; never touch hooks we didn't install.
|
|
165
|
+
const knownHooks = [
|
|
166
|
+
'check-cwd.js', 'check-stale-work-items.js', 'check-services.js',
|
|
167
|
+
'precompact-log.js', 'postcompact-log.js', 'restart-brief.js',
|
|
168
|
+
'rate-limit-retry.js', 'post-work-check.js', 'no-stop-open-epics.js',
|
|
169
|
+
'require-work-item-on-commit.js', 'verify-rdc-skills.js',
|
|
170
|
+
];
|
|
171
|
+
let removed = 0;
|
|
172
|
+
for (const f of knownHooks) {
|
|
173
|
+
if (!sourceFiles.has(f) && fs.existsSync(path.join(hooksDstDir, f))) {
|
|
174
|
+
try { fs.unlinkSync(path.join(hooksDstDir, f)); removed++; } catch {}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return removed;
|
|
178
|
+
}
|
|
179
|
+
|
|
123
180
|
// ── Cache flush helper ────────────────────────────────────────────────────────
|
|
124
181
|
function flushOldCaches(cacheBase, keepVersion) {
|
|
125
182
|
if (!fs.existsSync(cacheBase)) return 0;
|
|
@@ -480,6 +537,20 @@ async function main() {
|
|
|
480
537
|
warn('[0/6] git pull failed — installing from local copy');
|
|
481
538
|
}
|
|
482
539
|
|
|
540
|
+
// 0.5a. User-skills cleanup — remove any rdc: skills from ~/.claude/skills/user/
|
|
541
|
+
// (older installer versions wrote there; plugin cache is the only authoritative source)
|
|
542
|
+
{
|
|
543
|
+
const userSkillsDir = path.join(claudeHome, 'skills', 'user');
|
|
544
|
+
const purged = cleanUserSkills(userSkillsDir);
|
|
545
|
+
if (purged > 0) ok(`[0.5a] Skills cleanup — removed ${purged} stale rdc: skill(s) from skills/user/`);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// 0.5b. Stale hook cleanup — remove hooks we no longer ship
|
|
549
|
+
{
|
|
550
|
+
const staleRemoved = cleanStaleHooks(hooksDst, hooksSrc);
|
|
551
|
+
if (staleRemoved > 0) ok(`[0.5b] Hook cleanup — removed ${staleRemoved} orphaned hook file(s)`);
|
|
552
|
+
}
|
|
553
|
+
|
|
483
554
|
// 0.5. Legacy cleanup — remove old commands/rdc/ (pre-plugin-system format)
|
|
484
555
|
const legacyCommandsDir = path.join(claudeHome, 'commands', 'rdc');
|
|
485
556
|
if (fs.existsSync(legacyCommandsDir)) {
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -96,3 +96,41 @@ choose the most conservative/reversible approach and document the decision.
|
|
|
96
96
|
- Reference affected CLAUDE.md files in each work package description
|
|
97
97
|
- Reference the relevant guide file from `.rdc/guides/` (fallback: `.rdc/guides/`) for agent context
|
|
98
98
|
- **If a work package involves creating a new deployed app:** the task description MUST say "Use `rdc:deploy new <slug>` — do NOT create the Coolify app manually. Read `docs/runbooks/coolify-app-templates.json` first." Assign it to an `infra` agent. This is a hard rule — manually created apps have consistently been misconfigured.
|
|
99
|
+
|
|
100
|
+
## New App Q&A (mandatory before writing any infra task that creates a Coolify app)
|
|
101
|
+
|
|
102
|
+
If the plan includes deploying a new app, these questions MUST be answered — in interactive mode, ask the user; in unattended mode, escalate via advisor. Do NOT write the infra task until all answers are locked in. Record answers in the plan doc and embed them directly in the task description.
|
|
103
|
+
|
|
104
|
+
**Never guess. Wrong project = delete and recreate. There is no move operation in Coolify.**
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
Q1. Which Coolify project does this app belong to?
|
|
108
|
+
→ Read docs/runbooks/coolify-app-templates.json → _infrastructure.projects
|
|
109
|
+
→ Match by area: design-system / prt / rdc / rdc-marketing / zoen / lifeai / place-fund / infrastructure / ai-platform
|
|
110
|
+
→ If unsure: ASK. Do not infer from app name alone.
|
|
111
|
+
→ Record: project_uuid + environment_uuid (staging or production)
|
|
112
|
+
|
|
113
|
+
Q2. What is the domain?
|
|
114
|
+
→ *.dev.place.fund subdomain? (staging / internal tools)
|
|
115
|
+
→ Custom subdomain on an existing zone? (e.g. app.regendevcorp.com)
|
|
116
|
+
→ Apex domain? (e.g. place.fund itself)
|
|
117
|
+
→ Domain on a different zone entirely? (e.g. skymesasouth.com)
|
|
118
|
+
|
|
119
|
+
Q3. Is this domain already in our Cloudflare account?
|
|
120
|
+
→ Yes, zone exists → which zone?
|
|
121
|
+
→ No → who controls the nameservers? Does the registrar point NS to Cloudflare?
|
|
122
|
+
→ If NS not delegated to Cloudflare: A record in Cloudflare does nothing — must go to registrar
|
|
123
|
+
|
|
124
|
+
Q4. Does this app need Cloudflare proxy (orange cloud)?
|
|
125
|
+
→ *.dev.place.fund: NEVER proxy — breaks Traefik Let's Encrypt HTTP-01 cert provisioning
|
|
126
|
+
→ Custom domain needing DDoS/CDN: proxy OK only if SSL mode = Full (strict) + origin cert provisioned
|
|
127
|
+
→ Any doubt: start unproxied, add proxy after confirming SSL works
|
|
128
|
+
|
|
129
|
+
Q5. What SSL path?
|
|
130
|
+
→ Traefik + Let's Encrypt (default for all unproxied): automatic, no action needed
|
|
131
|
+
→ Cloudflare proxy + Full (strict): need origin cert from Cloudflare dashboard first
|
|
132
|
+
→ Nixpacks build pack: DO NOT USE for any app that needs custom SSL setup — nixpacks
|
|
133
|
+
containers have incompatible SSL configuration requirements. Use dockerfile build pack only.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Embed all five answers into the infra task description verbatim before handing to the agent.
|