@lifeaitools/rdc-skills 0.37.5 → 0.37.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rdc",
3
- "version": "0.37.5",
3
+ "version": "0.37.7",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code — plan, build, review, overnight unattended builds with work-item tracking and TDD enforcement.",
5
5
  "author": {
6
6
  "name": "LIFEAI",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema": "lifeai.plugin.v1",
3
3
  "id": "rdc-skills",
4
- "version": "0.37.5",
4
+ "version": "0.37.7",
5
5
  "publisher": "LIFEAI",
6
6
  "core": false,
7
7
  "documentation": {
package/git-sha.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "sha": "a96832c1aa663240fecf042c6b41d7017c8bce47"
2
+ "sha": "9621389d4e4724ae260e0d4e91651c10b3ac0e2c"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/rdc-skills",
3
- "version": "0.37.5",
3
+ "version": "0.37.7",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code - plan, build, review, overnight builds",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -19,7 +19,7 @@
19
19
  "type": "plugin",
20
20
  "skills": "skills/",
21
21
  "guides": "guides/",
22
- "version": "0.37.5",
22
+ "version": "0.37.7",
23
23
  "commands": "commands/"
24
24
  },
25
25
  "bin": {
@@ -951,7 +951,7 @@ function findCodexTargets() {
951
951
  return targets;
952
952
  }
953
953
 
954
- function registerCodexTarget(targetDir) {
954
+ function registerCodexTarget(targetDir, { install = false } = {}) {
955
955
  fs.mkdirSync(targetDir, { recursive: true });
956
956
 
957
957
  // Clean: remove dirs that are rdc skills — by prefix OR by frontmatter name
@@ -967,11 +967,21 @@ function registerCodexTarget(targetDir) {
967
967
  }
968
968
  }
969
969
 
970
- // Do not reinstall file-based copies. Codex discovers the live catalog via
971
- // [mcp_servers.rdc-skills]. Keeping the same skills in ~/.codex and ~/.agents
972
- // registers every skill two or three times, exhausts Codex's skill metadata
973
- // budget, and emits a red startup error on every session.
974
- return { removed, copied: 0 };
970
+ if (!install) return { removed, copied: 0 };
971
+
972
+ // Install into exactly ONE Codex skill dir. Copies in both ~/.codex and
973
+ // ~/.agents registered every skill twice and exhausted Codex's skill metadata
974
+ // budget; bf88292 answered that by installing none, which left Codex with
975
+ // rdc: skills only while the remote MCP was reachable.
976
+ const skillsSrc = path.join(repoRoot, 'skills');
977
+ let copied = 0;
978
+ for (const entry of fs.readdirSync(skillsSrc, { withFileTypes: true })) {
979
+ if (!entry.isDirectory()) continue;
980
+ if (!fs.existsSync(path.join(skillsSrc, entry.name, 'SKILL.md'))) continue;
981
+ copyDirRecursive(path.join(skillsSrc, entry.name), path.join(targetDir, `rdc-${entry.name}`));
982
+ copied++;
983
+ }
984
+ return { removed, copied };
975
985
  }
976
986
 
977
987
  // ── Step 6: Zip for claude.ai / distribution ─────────────────────────────────
@@ -1372,21 +1382,24 @@ async function main() {
1372
1382
  info('[2.5] MCP — rdc-skills endpoint verified (claude + codex)');
1373
1383
  }
1374
1384
 
1375
- // 2.6. Codex migration: MCP is authoritative; purge legacy file copies.
1385
+ // 2.6. Codex: rdc skill files in ONE dir (the explicit one, else ~/.codex/skills);
1386
+ // every other Codex skill dir is only cleaned, so nothing registers twice.
1376
1387
  const codexTargets = findCodexTargets();
1377
- if (codexTargets.length > 0) {
1378
- let copiedTotal = 0;
1379
- let removedTotal = 0;
1380
- for (const target of codexTargets) {
1381
- const { removed, copied } = registerCodexTarget(target.targetDir);
1382
- copiedTotal += copied;
1383
- removedTotal += removed;
1384
- info(` ${target.label.padEnd(15)}: ${target.targetDir} (${removed} stale removed; MCP authoritative)`);
1385
- }
1386
- ok(`[2.6] Codex — ${removedTotal} stale file-based skill(s) removed across ${codexTargets.length} target(s); MCP authoritative`);
1387
- } else {
1388
- info('[2.6] Codex — skipped (no Codex skill dirs found; use --codex-root or --codex-skill-dir)');
1389
- }
1388
+ const primaryCodexDir = explicitCodexSkillDir || path.join(os.homedir(), '.codex', 'skills');
1389
+ if (!codexTargets.some((t) => t.targetDir === primaryCodexDir)) {
1390
+ codexTargets.unshift({ label: 'global .codex', targetDir: primaryCodexDir });
1391
+ }
1392
+ let copiedTotal = 0;
1393
+ let removedTotal = 0;
1394
+ for (const target of codexTargets) {
1395
+ const install = target.targetDir === primaryCodexDir;
1396
+ const { removed, copied } = registerCodexTarget(target.targetDir, { install });
1397
+ copiedTotal += copied;
1398
+ removedTotal += removed;
1399
+ info(` ${target.label.padEnd(15)}: ${target.targetDir} (${install ? `${copied} installed` : 'cleaned only'}, ${removed} stale removed)`);
1400
+ }
1401
+ if (copiedTotal === 0) throw new Error(`Codex skill install wrote nothing to ${primaryCodexDir}`);
1402
+ ok(`[2.6] Codex — ${copiedTotal} skill(s) installed in ${primaryCodexDir}; ${removedTotal} stale copies removed across ${codexTargets.length} dir(s)`);
1390
1403
 
1391
1404
  // 2.7. Symlinks in regen-root/.claude/skills/ (FS MCP + claude.ai access)
1392
1405
  if (codexRoot) {
@@ -178,10 +178,16 @@ function checkCodex(truth) {
178
178
  const rdcDirs = dirs.filter((e) => /^rdc-/.test(e.name) || readFrontmatterName(path.join(t.dir, e.name, 'SKILL.md'))?.startsWith('rdc:'));
179
179
  results.push({ label: t.label, dir: t.dir, count: rdcDirs.length });
180
180
  }
181
- const pass = results.every((r) => r.count === 0);
182
- const detail = results.map((r) =>
183
- `${r.label}: ${r.count} legacy file-based rdc skill(s)${r.count === 0 ? '' : ' [MCP DUPLICATES PRESENT]'}`
184
- ).join('; ');
181
+ // Codex keeps rdc skills as files in exactly one dir (~/.codex/skills), so it
182
+ // works without the network; any copy elsewhere registers the skill twice.
183
+ const skillsSrc = path.join(repoRoot, 'skills');
184
+ const expected = fs.readdirSync(skillsSrc, { withFileTypes: true })
185
+ .filter((e) => e.isDirectory() && fs.existsSync(path.join(skillsSrc, e.name, 'SKILL.md'))).length;
186
+ const isPrimary = (r) => r.label === 'global .codex';
187
+ const pass = results.some(isPrimary) && results.every((r) => (isPrimary(r) ? r.count === expected : r.count === 0));
188
+ const detail = results.map((r) => (isPrimary(r)
189
+ ? `${r.label}: ${r.count}/${expected} rdc skill(s) installed`
190
+ : `${r.label}: ${r.count} rdc skill(s)${r.count === 0 ? '' : ' [DUPLICATES — would register twice]'}`)).join('; ');
185
191
  return { surface: 'Codex', pass, detail };
186
192
  }
187
193
 
@@ -27,6 +27,20 @@ Run it from the regen-root checkout you are working in. That is the whole
27
27
  instruction. There is no checklist to follow, no mode to pick, and no decision
28
28
  for you to make on the success path.
29
29
 
30
+ ## Local build contract
31
+
32
+ Standard dev deployment builds on the workstation first. `DEPLOY_MGR_URL`
33
+ must name a loopback manager whose health response reports `host.role: local`.
34
+ The program requests `builder: local` explicitly; Docker or build failure stops
35
+ the deployment. It never falls back to a remote builder.
36
+
37
+ The target must have a registered image route. Legacy remote build/reload routes
38
+ are refused until a proper local artifact build-and-ship route is implemented.
39
+ Do not enable an image route without its runtime and build configuration.
40
+
41
+ The manager's explicitly requested remote maintenance operations remain separate
42
+ from this standard command. `promote` remains build-free and approval-gated.
43
+
30
44
  ## Exit 0 — you are done
31
45
 
32
46
  Print the URL the program reports, and stop.
@@ -46,8 +60,8 @@ followed by the same record as one line of JSON.
46
60
  | exit | meaning | first move |
47
61
  |---|---|---|
48
62
  | 2 | usage — bad or missing arguments | read the usage line; this program takes a slug and optionally `promote` |
49
- | 3 | deploy manager unreachable | `pm2 restart regen-deploy-mgr` (it is a local PM2 process), then re-run |
50
- | 4 | slug not resolvable or not routable | the block names what is missing — a registry row, or an allowlist entry |
63
+ | 3 | deploy manager unavailable or unsuitable for local building | read the block; restore the workstation manager and its local host identity, then re-run |
64
+ | 4 | slug not resolvable or no local artifact route | the block names the missing registry or image route; repair that route before deployment |
51
65
  | 5 | a submitted job failed or was rejected | the block carries the manager's own step, command, exit code and stderr tail |
52
66
  | 6 | the job succeeded but the health probe did not | bytes shipped, app did not come up — read the job the block names |
53
67
  | 7 | polling exceeded the deadline | the job is NOT cancelled; the block gives the URL to read it |
@@ -110,9 +124,10 @@ manager, where it runs, rather than in a document that hopes to be read.
110
124
 
111
125
  A dev deploy needs no approval. `promote` puts bytes on production and needs
112
126
  explicit go-ahead for that call. The program itself refuses to promote anything
113
- that is not an image-model app, because promote retags the digest dev already
114
- runs — **a promote never builds**, and one that fell back to building would ship
115
- bytes production has never seen under a name claiming it had.
127
+ that is not an image-model app. **A promote never builds**; it retags an existing
128
+ image through the manager. The current manager resolves the configured dev tag
129
+ (normally `develop`); a successful dev deploy alone does not prove that this
130
+ mutable tag still identifies the running dev image when promotion begins.
116
131
 
117
132
  ## Verification
118
133