@lifeaitools/rdc-skills 0.9.36 → 0.9.38

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.
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ // Behavioral smoke tests for the RDC marker and Stop output-contract hooks.
3
+
4
+ import { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join, resolve, dirname } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { spawnSync } from "node:child_process";
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const REPO_ROOT = resolve(__dirname, "..");
12
+ const MARKER_HOOK = join(REPO_ROOT, "hooks", "rdc-invocation-marker.js");
13
+ const STOP_HOOK = join(REPO_ROOT, "hooks", "rdc-output-contract-gate.js");
14
+
15
+ const tmpHome = mkdtempSync(join(tmpdir(), "rdc-hooks-"));
16
+ const env = { ...process.env, HOME: tmpHome, USERPROFILE: tmpHome };
17
+ const failures = [];
18
+
19
+ function markerPath(sessionId) {
20
+ return join(tmpHome, ".claude", "rdc-active", `${sessionId}.json`);
21
+ }
22
+
23
+ function runHook(script, payload) {
24
+ return spawnSync(process.execPath, [script], {
25
+ input: JSON.stringify(payload),
26
+ encoding: "utf8",
27
+ env,
28
+ });
29
+ }
30
+
31
+ function assert(name, condition, detail = "") {
32
+ if (!condition) failures.push(`${name}${detail ? `: ${detail}` : ""}`);
33
+ }
34
+
35
+ function readMarker(sessionId) {
36
+ return JSON.parse(readFileSync(markerPath(sessionId), "utf8"));
37
+ }
38
+
39
+ try {
40
+ const expansion = runHook(MARKER_HOOK, {
41
+ hook_event_name: "UserPromptExpansion",
42
+ session_id: "s-expansion",
43
+ command_source: "plugin",
44
+ command_name: "rdc:design",
45
+ prompt: "/rdc:design palette audit",
46
+ });
47
+ assert("expansion exits zero", expansion.status === 0, expansion.stderr);
48
+ assert("expansion emits context", /RDC CONTRACT ACTIVE/.test(expansion.stdout), expansion.stdout);
49
+ assert("expansion writes marker", existsSync(markerPath("s-expansion")));
50
+ assert("expansion marker event preserved", readMarker("s-expansion").hook_event_name === "UserPromptExpansion");
51
+
52
+ const builtin = runHook(MARKER_HOOK, {
53
+ hook_event_name: "UserPromptExpansion",
54
+ session_id: "s-builtin",
55
+ command_source: "builtin",
56
+ command_name: "help",
57
+ prompt: "/help",
58
+ });
59
+ assert("builtin exits zero", builtin.status === 0, builtin.stderr);
60
+ assert("builtin emits no context", builtin.stdout.trim() === "", builtin.stdout);
61
+ assert("builtin writes no marker", !existsSync(markerPath("s-builtin")));
62
+
63
+ const submit1 = runHook(MARKER_HOOK, {
64
+ hook_event_name: "UserPromptExpansion",
65
+ session_id: "s-dedup",
66
+ command_source: "plugin",
67
+ command_name: "rdc:design",
68
+ prompt: "/rdc:design button audit",
69
+ });
70
+ assert("dedup first mark exits zero", submit1.status === 0, submit1.stderr);
71
+ const first = readMarker("s-dedup");
72
+ const submit2 = runHook(MARKER_HOOK, {
73
+ hook_event_name: "UserPromptSubmit",
74
+ session_id: "s-dedup",
75
+ prompt: "/rdc:design button audit",
76
+ });
77
+ assert("dedup second mark exits zero", submit2.status === 0, submit2.stderr);
78
+ const second = readMarker("s-dedup");
79
+ assert("dedup preserves started_at", second.started_at === first.started_at);
80
+ assert("dedup preserves hook event", second.hook_event_name === "UserPromptExpansion");
81
+
82
+ const genericHelp = runHook(MARKER_HOOK, {
83
+ hook_event_name: "UserPromptSubmit",
84
+ session_id: "s-help",
85
+ prompt: "/help",
86
+ });
87
+ assert("generic help exits zero", genericHelp.status === 0, genericHelp.stderr);
88
+ assert("generic help writes no marker", !existsSync(markerPath("s-help")));
89
+
90
+ const noMarker = runHook(STOP_HOOK, {
91
+ hook_event_name: "Stop",
92
+ session_id: "s-no-marker",
93
+ last_assistant_message: "plain chat",
94
+ });
95
+ assert("stop without marker exits zero", noMarker.status === 0, noMarker.stderr);
96
+ assert("stop without marker is silent", noMarker.stdout.trim() === "", noMarker.stdout);
97
+
98
+ writeFileSync(markerPath("s-block"), JSON.stringify({
99
+ session_id: "s-block",
100
+ command: "design",
101
+ started_at: new Date().toISOString(),
102
+ }, null, 2));
103
+ const blocked = runHook(STOP_HOOK, {
104
+ hook_event_name: "Stop",
105
+ session_id: "s-block",
106
+ last_assistant_message: "No contract artifacts here.",
107
+ });
108
+ assert("noncompliant stop exits zero", blocked.status === 0, blocked.stderr);
109
+ assert("noncompliant stop blocks", /"decision"\s*:\s*"block"/.test(blocked.stdout), blocked.stdout);
110
+ assert("noncompliant stop retains marker", existsSync(markerPath("s-block")));
111
+
112
+ const reentry = runHook(STOP_HOOK, {
113
+ hook_event_name: "Stop",
114
+ session_id: "s-block",
115
+ stop_hook_active: true,
116
+ last_assistant_message: "Still no contract artifacts.",
117
+ });
118
+ assert("stop reentry exits zero", reentry.status === 0, reentry.stderr);
119
+ assert("stop reentry allows silent pass", reentry.stdout.trim() === "", reentry.stdout);
120
+ assert("stop reentry clears marker", !existsSync(markerPath("s-block")));
121
+
122
+ writeFileSync(markerPath("s-pass"), JSON.stringify({
123
+ session_id: "s-pass",
124
+ command: "review",
125
+ started_at: new Date().toISOString(),
126
+ }, null, 2));
127
+ const compliant = runHook(STOP_HOOK, {
128
+ hook_event_name: "Stop",
129
+ session_id: "s-pass",
130
+ last_assistant_message: "[x] Verified hook behavior\n\n✅ Complete in 2s",
131
+ });
132
+ assert("compliant stop exits zero", compliant.status === 0, compliant.stderr);
133
+ assert("compliant stop is silent", compliant.stdout.trim() === "", compliant.stdout);
134
+ assert("compliant stop clears marker", !existsSync(markerPath("s-pass")));
135
+ } finally {
136
+ rmSync(tmpHome, { recursive: true, force: true });
137
+ }
138
+
139
+ if (failures.length > 0) {
140
+ console.error("\nrdc hook behavior tests — FAIL\n");
141
+ for (const failure of failures) console.error(` - ${failure}`);
142
+ process.exit(1);
143
+ }
144
+
145
+ console.log("rdc hook behavior tests — PASS");
@@ -301,8 +301,8 @@ Read the task title and description, then:
301
301
  ⚠️ The validator does NOT use `isolation: "worktree"` — it must read the fully merged develop branch. Omit the isolation parameter for this dispatch only.
302
302
 
303
303
  ```
304
- "Read C:/Dev/regen-root/.rdc/guides/agent-bootstrap.md then C:/Dev/regen-root/.rdc/guides/verify.md.
305
- Read C:/Dev/regen-root/.rdc/guides/engineering-behavior.md before validating scope, deviations, and evidence.
304
+ "Read {PROJECT_ROOT}/.rdc/guides/agent-bootstrap.md then {PROJECT_ROOT}/.rdc/guides/verify.md.
305
+ Read {PROJECT_ROOT}/.rdc/guides/engineering-behavior.md before validating scope, deviations, and evidence.
306
306
  Validate these work items: [list of IDs and titles].
307
307
  Apps touched: [list].
308
308
  Git diff since build start: [attach or reference].
@@ -110,7 +110,7 @@ the source of truth.
110
110
  "skill": "rdc:review",
111
111
  "task": "Audit the current diff for regressions before merge.",
112
112
  "context": {
113
- "repo": "C:\\Dev\\regen-root",
113
+ "repo": "{PROJECT_ROOT}",
114
114
  "work_item_id": "<optional-uuid>",
115
115
  "branch": "develop",
116
116
  "owned_files": []
@@ -66,10 +66,10 @@ Template selection:
66
66
 
67
67
  ```
68
68
  rdc:deploy new: <slug>
69
- [ ] .dockerignore present at regen-root root (ls C:/Dev/regen-root/.dockerignore — STOP if missing)
69
+ [ ] .dockerignore present at project root (`ls {PROJECT_ROOT}/.dockerignore` — STOP if missing)
70
70
  [ ] Template loaded from docs/runbooks/coolify-app-templates.json (pick nextjs-app / static-site / mcp-server)
71
71
  [ ] Required vars substituted: NAME, APP_PATH, DOMAIN, BRANCH, PROJECT_UUID, ENVIRONMENT_UUID [+ TURBO_FILTER / PORT]
72
- [ ] DNS path chosen (A: *.dev.place.fund B: apex C: other zone)
72
+ [ ] DNS path chosen (A: staging wildcard B: apex C: other zone)
73
73
  [ ] DNS record verified or wildcard confirmed
74
74
  [ ] Cloudflare proxy setting correct for DNS path
75
75
  [ ] Application created via POST /applications/private-github-app (template payload)
@@ -117,7 +117,7 @@ rdc:deploy audit: fleet scan
117
117
  [ ] Env var drift (registry.env_vars_needed vs Coolify env)
118
118
  [ ] Branch mismatches (Coolify git_branch ≠ expected)
119
119
  [ ] Disk space on 64.237.54.189
120
- [ ] CF proxy misconfigs on *.dev.place.fund
120
+ [ ] DNS/proxy misconfigs on configured staging wildcard
121
121
  [ ] Duplicate apps (same repo, multiple UUIDs)
122
122
 
123
123
  Findings:
@@ -145,39 +145,39 @@ _COOLIFY=$(curl -s http://127.0.0.1:52437/v/coolify-api)
145
145
 
146
146
  # List applications
147
147
  curl -s -H "Authorization: Bearer $_COOLIFY" \
148
- https://deploy.regendevcorp.com/api/v1/applications
148
+ "$DEPLOY_API_BASE/api/v1/applications"
149
149
 
150
150
  # Get application details
151
151
  curl -s -H "Authorization: Bearer $_COOLIFY" \
152
- https://deploy.regendevcorp.com/api/v1/applications/<uuid>
152
+ "$DEPLOY_API_BASE/api/v1/applications/<uuid>"
153
153
 
154
154
  # Deploy (trigger)
155
155
  curl -s -X POST -H "Authorization: Bearer $_COOLIFY" \
156
- https://deploy.regendevcorp.com/api/v1/applications/<uuid>/deploy
156
+ "$DEPLOY_API_BASE/api/v1/applications/<uuid>/deploy"
157
157
 
158
158
  # Get deployment logs
159
159
  curl -s -H "Authorization: Bearer $_COOLIFY" \
160
- https://deploy.regendevcorp.com/api/v1/deployments/<deployment-id>
160
+ "$DEPLOY_API_BASE/api/v1/deployments/<deployment-id>"
161
161
 
162
162
  # Set env var
163
163
  curl -s -X POST -H "Authorization: Bearer $_COOLIFY" \
164
164
  -H "Content-Type: application/json" \
165
165
  -d '{"key":"<KEY>","value":"<VALUE>"}' \
166
- https://deploy.regendevcorp.com/api/v1/applications/<uuid>/envs
166
+ "$DEPLOY_API_BASE/api/v1/applications/<uuid>/envs"
167
167
 
168
168
  # Set watch_paths
169
169
  curl -s -X PATCH -H "Authorization: Bearer $_COOLIFY" \
170
170
  -H "Content-Type: application/json" \
171
171
  -d '{"watch_paths":"apps/<name>/**\npackages/**"}' \
172
- https://deploy.regendevcorp.com/api/v1/applications/<uuid>
172
+ "$DEPLOY_API_BASE/api/v1/applications/<uuid>"
173
173
  ```
174
174
 
175
175
  **Never print `$_COOLIFY` to stdout.** Inline from clauth only — do not assign raw strings.
176
176
 
177
177
  If clauth daemon is not responding (`curl -s http://127.0.0.1:52437/ping` fails):
178
178
  ```
179
- BLOCKED: clauth daemon is not responding.
180
- Fix: Run C:\Dev\regen-root\scripts\restart-clauth.bat, then unlock at http://127.0.0.1:52437
179
+ BLOCKED: credential provider is not responding.
180
+ Fix: start the project's credential provider or configure deployment credentials through env vars, then retry.
181
181
  I cannot proceed until this is resolved.
182
182
  ```
183
183
 
@@ -189,7 +189,7 @@ I cannot proceed until this is resolved.
189
189
  ```
190
190
  Server UUID: ih386anenvvvn6fy1umtyow0
191
191
  Server IP: 64.237.54.189
192
- Dashboard: https://deploy.regendevcorp.com
192
+ Dashboard: <deployment-dashboard-url>
193
193
  GitHub App UUID: xdmcy60putp5h9j7k4kwg9c3
194
194
  ```
195
195
 
@@ -19,7 +19,7 @@ RDC-owned design execution for Studio and LIFEAI interfaces. This skill is the S
19
19
 
20
20
  - Studio, Palette Library, brand-token, theme, component, or live-editor work
21
21
  - Any design task that must understand RDC's real token tables and Studio routes
22
- - UI critique, audit, polish, colorize, type, layout, or craft work in `regen-root`
22
+ - UI critique, audit, polish, colorize, type, layout, or craft work in `{PROJECT_ROOT}`
23
23
  - Agent-side color-system exploration using Rampa CLI
24
24
  - Preparing token-aware implementation instructions for frontend/backend/data agents
25
25
 
@@ -166,7 +166,7 @@ Project docs to read for Studio work:
166
166
  8. **Verify.**
167
167
  - Run scoped tests only.
168
168
  - For Studio: prefer route smoke checks, token API checks, and browser screenshots when UI changed.
169
- - For CLI prompt work: run `node C:/Dev/rdc-skills/scripts/rdc-design-cli.mjs <command> <brief>` and inspect the generated report under `.rdc/reports/rdc-design-cli/`.
169
+ - For CLI prompt work: run `node {RDC_SKILLS_ROOT}/scripts/rdc-design-cli.mjs <command> <brief>` and inspect the generated report under `.rdc/reports/rdc-design-cli/`.
170
170
 
171
171
  ## Command Menu
172
172
 
@@ -188,15 +188,15 @@ Project docs to read for Studio work:
188
188
  Use the local helper to see exactly how much instruction text the skill is generating before sending it through an agent:
189
189
 
190
190
  ```powershell
191
- node C:/Dev/rdc-skills/scripts/rdc-design-cli.mjs studio "audit the Studio palette page"
192
- node C:/Dev/rdc-skills/scripts/rdc-design-cli.mjs palette "generate a PRT palette workflow"
193
- node C:/Dev/rdc-skills/scripts/rdc-design-cli.mjs --json theme "RDC earth-forward light theme"
191
+ node {RDC_SKILLS_ROOT}/scripts/rdc-design-cli.mjs studio "audit the Studio palette page"
192
+ node {RDC_SKILLS_ROOT}/scripts/rdc-design-cli.mjs palette "generate a PRT palette workflow"
193
+ node {RDC_SKILLS_ROOT}/scripts/rdc-design-cli.mjs --json theme "RDC earth-forward light theme"
194
194
  ```
195
195
 
196
196
  The helper writes logs to:
197
197
 
198
198
  ```text
199
- C:/Dev/rdc-skills/.rdc/reports/rdc-design-cli/
199
+ {RDC_SKILLS_ROOT}/.rdc/reports/rdc-design-cli/
200
200
  ```
201
201
 
202
202
  Each run includes character count, word count, approximate token count, references loaded, and the final prompt text.
@@ -11,7 +11,7 @@ description: "Usage `rdc:fs-mcp <task>` — Use the File System MCP bridge for l
11
11
  # rdc:fs-mcp — File System MCP Bridge
12
12
 
13
13
  ## When to Use
14
- - Claude.ai, Cowork, or another remote surface needs live access to `C:/Dev/regen-root` through the File System MCP.
14
+ - Claude.ai, Cowork, or another remote surface needs live access to `{PROJECT_ROOT}` through the File System MCP.
15
15
  - You need to read, search, or list current local repo files without relying on GitHub freshness.
16
16
  - You need to write a small/scratch file through FS MCP.
17
17
  - You need to move a larger cloud file into the local repo.
@@ -88,7 +88,7 @@ Required Claude.ai handoff shape:
88
88
 
89
89
  ```json
90
90
  {
91
- "repo": "LIFEAI/regen-root",
91
+ "repo": "<owner>/<repo>",
92
92
  "remote": "origin",
93
93
  "ref": "claude-ai/docs-upload-123",
94
94
  "paths": ["docs/plans/foo.md"],
@@ -227,7 +227,7 @@ Q1. Which Coolify project does this app belong to?
227
227
  → Record: project_uuid + environment_uuid (staging or production)
228
228
 
229
229
  Q2. What is the domain?
230
- *.dev.place.fund subdomain? (staging / internal tools)
230
+ staging wildcard subdomain? (staging / internal tools)
231
231
  → Custom subdomain on an existing zone? (e.g. app.regendevcorp.com)
232
232
  → Apex domain? (e.g. place.fund itself)
233
233
  → Domain on a different zone entirely? (e.g. skymesasouth.com)
@@ -238,7 +238,7 @@ Q3. Is this domain already in our Cloudflare account?
238
238
  → If NS not delegated to Cloudflare: A record in Cloudflare does nothing — must go to registrar
239
239
 
240
240
  Q4. Does this app need Cloudflare proxy (orange cloud)?
241
- *.dev.place.fund: NEVER proxy — breaks Traefik Let's Encrypt HTTP-01 cert provisioning
241
+ → Traefik/Let's Encrypt HTTP-01 staging wildcards are often safest unproxied; verify your platform's DNS requirements.
242
242
  → Custom domain needing DDoS/CDN: proxy OK only if SSL mode = Full (strict) + origin cert provisioned
243
243
  → Any doubt: start unproxied, add proxy after confirming SSL works
244
244