@lifeaitools/rdc-skills 0.35.5 → 0.35.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.
Files changed (106) hide show
  1. package/.claude-plugin/plugin.json +180 -44
  2. package/.github/workflows/self-test.yml +34 -34
  3. package/CHANGELOG.md +393 -393
  4. package/MANIFEST.md +224 -224
  5. package/README.md +10 -3
  6. package/clauth-plugin.json +1 -1
  7. package/commands/analyze-tests.md +1 -4
  8. package/commands/build.md +1 -2
  9. package/commands/check-clean-code.md +1 -3
  10. package/commands/check-packages.md +1 -3
  11. package/commands/collab.md +1 -2
  12. package/commands/compare-compliance.md +1 -4
  13. package/commands/deploy.md +1 -2
  14. package/commands/design.md +1 -2
  15. package/commands/edit.md +1 -2
  16. package/commands/fixit.md +1 -2
  17. package/commands/flow.md +5 -6
  18. package/commands/full-analysis.md +1 -7
  19. package/commands/get-refactoring-plan.md +1 -5
  20. package/commands/handoff.md +1 -2
  21. package/commands/help.md +1 -3
  22. package/commands/mode.md +4 -5
  23. package/commands/overnight.md +1 -2
  24. package/commands/plan.md +1 -2
  25. package/commands/preplan.md +1 -2
  26. package/commands/prototype.md +1 -2
  27. package/commands/quick-check.md +1 -4
  28. package/commands/recover.md +1 -2
  29. package/commands/release.md +2 -2
  30. package/commands/report.md +1 -2
  31. package/commands/review-arch.md +1 -4
  32. package/commands/review.md +1 -5
  33. package/commands/self-test.md +1 -2
  34. package/commands/status.md +1 -2
  35. package/commands/suggest-patterns.md +1 -4
  36. package/commands/validate-solid.md +1 -3
  37. package/commands/watch.md +1 -2
  38. package/commands/workitems.md +1 -2
  39. package/guides/agents/backend.md +102 -102
  40. package/guides/agents/content.md +94 -94
  41. package/guides/agents/cs2.md +56 -56
  42. package/guides/agents/data.md +86 -86
  43. package/guides/agents/design.md +77 -77
  44. package/guides/agents/frontend.md +91 -91
  45. package/guides/agents/infrastructure.md +81 -81
  46. package/guides/agents/setup.md +272 -272
  47. package/guides/agents/verify.md +119 -119
  48. package/guides/agents/viz.md +106 -106
  49. package/guides/orchestration-epic.md +17 -17
  50. package/hooks/require-work-item-on-commit.js +69 -4
  51. package/package.json +1 -1
  52. package/scripts/gen-skill-descriptions.mjs +190 -0
  53. package/scripts/self-test.mjs +1459 -1459
  54. package/skills/architecture-reviewer/SKILL.md +1 -11
  55. package/skills/behavior-audit/SKILL.md +1 -1
  56. package/skills/behavior-audit/agents/openai.yaml +4 -4
  57. package/skills/brochure/SKILL.md +1 -1
  58. package/skills/brochurify/SKILL.md +1 -1
  59. package/skills/build/SKILL.md +1 -1
  60. package/skills/channel-formatter/SKILL.md +1 -1
  61. package/skills/clean-code-analyzer/SKILL.md +1 -6
  62. package/skills/co-develop/SKILL.md +1 -1
  63. package/skills/collab/SKILL.md +3 -3
  64. package/skills/convert/SKILL.md +1 -1
  65. package/skills/deploy/SKILL.md +1 -1
  66. package/skills/design/SKILL.md +1 -1
  67. package/skills/edit/SKILL.md +1 -1
  68. package/skills/env/SKILL.md +57 -14
  69. package/skills/extract-verifier-rules/SKILL.md +1 -1
  70. package/skills/fixit/SKILL.md +1 -1
  71. package/skills/fs-mcp/SKILL.md +1 -1
  72. package/skills/handoff/SKILL.md +1 -1
  73. package/skills/help/SKILL.md +1 -1
  74. package/skills/housekeeping/SKILL.md +1 -1
  75. package/skills/lifeai-brochure-author/SKILL.md +1 -1
  76. package/skills/new-model/SKILL.md +1 -7
  77. package/skills/onramp/SKILL.md +1 -1
  78. package/skills/overnight/SKILL.md +1 -1
  79. package/skills/package-design/SKILL.md +1 -4
  80. package/skills/pattern-advisor/SKILL.md +1 -6
  81. package/skills/pattern-refactoring-guide/SKILL.md +1 -4
  82. package/skills/plan/SKILL.md +1 -1
  83. package/skills/preplan/SKILL.md +1 -1
  84. package/skills/prototype/SKILL.md +1 -1
  85. package/skills/refactor/SKILL.md +1 -1
  86. package/skills/regen-media/SKILL.md +1 -1
  87. package/skills/release/SKILL.md +1 -1
  88. package/skills/report/SKILL.md +1 -1
  89. package/skills/review/SKILL.md +1 -1
  90. package/skills/rpms-filemap/SKILL.md +1 -1
  91. package/skills/self-test/SKILL.md +1 -1
  92. package/skills/solid-validator/SKILL.md +1 -6
  93. package/skills/status/SKILL.md +1 -1
  94. package/skills/terminal-config/SKILL.md +1 -1
  95. package/skills/testing-strategy/SKILL.md +1 -6
  96. package/skills/tests/onramp.test.json +101 -101
  97. package/skills/tests/rdc-env.test.json +12 -12
  98. package/skills/tests/rdc-new-model.test.json +12 -12
  99. package/skills/tests/rdc-refactor.test.json +29 -29
  100. package/skills/tests/rdc-regen-media.test.json +29 -29
  101. package/skills/watch/SKILL.md +1 -1
  102. package/skills/workitems/SKILL.md +1 -1
  103. package/tests/clauth-plugin-postinstall.test.mjs +14 -1
  104. package/tests/help-surface.test.mjs +2 -2
  105. package/tests/require-work-item-on-commit.test.mjs +54 -0
  106. package/ecosystem.local.config.cjs +0 -18
@@ -1,101 +1,101 @@
1
- {
2
- "manifest_version": 1,
3
- "skill": "rdc:onramp",
4
- "description": "Tier-2 self-test for rdc:onramp enrollment skill",
5
- "tier": 2,
6
- "sandbox": true,
7
- "env": {
8
- "RDC_TEST": "1"
9
- },
10
- "invocation": {
11
- "slug": "onramp-selftest",
12
- "name": "Onramp Self Test",
13
- "flags": ["--archetype", "working-landscapes", "--dry-run"]
14
- },
15
- "fixture": {
16
- "prompt": "rdc:onramp onramp-selftest --name \"Onramp Self Test\" --archetype working-landscapes --dry-run",
17
- "env": { "RDC_\u0054EST": "1" },
18
- "slow": true
19
- },
20
- "assertions": {
21
- "exit_code": 0,
22
- "stdout_contains": ["Preflight", "Resolve drift"]
23
- },
24
- "acceptance": {
25
- "output_contains": ["Preflight", "Resolve drift", "disk-ahead", "already-enrolled"],
26
- "output_not_contains": ["hand-edit _context.md", "raw insert"]
27
- },
28
- "legacy_assertions": [
29
- {
30
- "type": "exit_code",
31
- "expect": 0,
32
- "description": "Skill exits cleanly under RDC_TEST with --dry-run"
33
- },
34
- {
35
- "type": "stdout_contains",
36
- "pattern": "Preflight",
37
- "description": "Checklist begins with Preflight step"
38
- },
39
- {
40
- "type": "stdout_contains",
41
- "pattern": "Resolve drift",
42
- "description": "Drift resolution step is emitted"
43
- },
44
- {
45
- "type": "stdout_contains",
46
- "pattern": "\\[RDC_TEST\\]",
47
- "description": "Sandbox short-circuit marker present — confirms external calls were skipped"
48
- },
49
- {
50
- "type": "file_absent",
51
- "path": "places/onramp-selftest/_context.md",
52
- "description": "Scaffolder MUST NOT write _context.md — projection-drift violation gate"
53
- }
54
- ],
55
- "door_contracts": [
56
- {
57
- "name": "enroll_place_signature",
58
- "description": "enroll_place RPC must accept (text, text, jsonb, text) and return jsonb",
59
- "type": "rpc_introspection",
60
- "project_id": "uvojezuorjgqzmhhgluu",
61
- "query": "SELECT p.proname, pg_get_function_identity_arguments(p.oid) AS args, pg_get_function_result(p.oid) AS returns FROM pg_proc p WHERE p.proname = 'enroll_place';",
62
- "expect_args_contains": ["text", "jsonb"],
63
- "expect_returns": "jsonb"
64
- },
65
- {
66
- "name": "insert_work_item_accepts_project_node_id",
67
- "description": "insert_work_item must accept p_project_node_id parameter",
68
- "type": "rpc_introspection",
69
- "project_id": "uvojezuorjgqzmhhgluu",
70
- "query": "SELECT proname, pg_get_function_identity_arguments(oid) FROM pg_proc WHERE proname = 'insert_work_item';",
71
- "expect_args_contains": ["p_project_node_id"]
72
- }
73
- ],
74
- "disk_ahead_test": {
75
- "description": "disk-ahead state must STOP and open a reconciliation work item",
76
- "setup": "mkdir -p places/disk-ahead-test",
77
- "invocation_slug": "disk-ahead-test",
78
- "invocation_name": "Disk Ahead Test",
79
- "assertions": [
80
- {
81
- "type": "stdout_contains",
82
- "pattern": "disk-ahead",
83
- "description": "Skill identifies the disk-ahead state"
84
- },
85
- {
86
- "type": "stdout_contains",
87
- "pattern": "STOP",
88
- "description": "Skill STOPs on disk-ahead"
89
- },
90
- {
91
- "type": "exit_nonzero",
92
- "description": "Skill exits non-zero on disk-ahead (not a clean enrollment)"
93
- }
94
- ],
95
- "teardown": "rmdir places/disk-ahead-test 2>/dev/null || true"
96
- },
97
- "idempotency_test": {
98
- "description": "Running rdc:onramp twice for already-enrolled should produce zero new writes",
99
- "note": "Under RDC_TEST=1 this is verified by checking that [RDC_TEST] skipping markers appear (not real insert calls) and the checklist reports already-enrolled"
100
- }
101
- }
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:onramp",
4
+ "description": "Tier-2 self-test for rdc:onramp enrollment skill",
5
+ "tier": 2,
6
+ "sandbox": true,
7
+ "env": {
8
+ "RDC_TEST": "1"
9
+ },
10
+ "invocation": {
11
+ "slug": "onramp-selftest",
12
+ "name": "Onramp Self Test",
13
+ "flags": ["--archetype", "working-landscapes", "--dry-run"]
14
+ },
15
+ "fixture": {
16
+ "prompt": "rdc:onramp onramp-selftest --name \"Onramp Self Test\" --archetype working-landscapes --dry-run",
17
+ "env": { "RDC_\u0054EST": "1" },
18
+ "slow": true
19
+ },
20
+ "assertions": {
21
+ "exit_code": 0,
22
+ "stdout_contains": ["Preflight", "Resolve drift"]
23
+ },
24
+ "acceptance": {
25
+ "output_contains": ["Preflight", "Resolve drift", "disk-ahead", "already-enrolled"],
26
+ "output_not_contains": ["hand-edit _context.md", "raw insert"]
27
+ },
28
+ "legacy_assertions": [
29
+ {
30
+ "type": "exit_code",
31
+ "expect": 0,
32
+ "description": "Skill exits cleanly under RDC_TEST with --dry-run"
33
+ },
34
+ {
35
+ "type": "stdout_contains",
36
+ "pattern": "Preflight",
37
+ "description": "Checklist begins with Preflight step"
38
+ },
39
+ {
40
+ "type": "stdout_contains",
41
+ "pattern": "Resolve drift",
42
+ "description": "Drift resolution step is emitted"
43
+ },
44
+ {
45
+ "type": "stdout_contains",
46
+ "pattern": "\\[RDC_TEST\\]",
47
+ "description": "Sandbox short-circuit marker present — confirms external calls were skipped"
48
+ },
49
+ {
50
+ "type": "file_absent",
51
+ "path": "places/onramp-selftest/_context.md",
52
+ "description": "Scaffolder MUST NOT write _context.md — projection-drift violation gate"
53
+ }
54
+ ],
55
+ "door_contracts": [
56
+ {
57
+ "name": "enroll_place_signature",
58
+ "description": "enroll_place RPC must accept (text, text, jsonb, text) and return jsonb",
59
+ "type": "rpc_introspection",
60
+ "project_id": "uvojezuorjgqzmhhgluu",
61
+ "query": "SELECT p.proname, pg_get_function_identity_arguments(p.oid) AS args, pg_get_function_result(p.oid) AS returns FROM pg_proc p WHERE p.proname = 'enroll_place';",
62
+ "expect_args_contains": ["text", "jsonb"],
63
+ "expect_returns": "jsonb"
64
+ },
65
+ {
66
+ "name": "insert_work_item_accepts_project_node_id",
67
+ "description": "insert_work_item must accept p_project_node_id parameter",
68
+ "type": "rpc_introspection",
69
+ "project_id": "uvojezuorjgqzmhhgluu",
70
+ "query": "SELECT proname, pg_get_function_identity_arguments(oid) FROM pg_proc WHERE proname = 'insert_work_item';",
71
+ "expect_args_contains": ["p_project_node_id"]
72
+ }
73
+ ],
74
+ "disk_ahead_test": {
75
+ "description": "disk-ahead state must STOP and open a reconciliation work item",
76
+ "setup": "mkdir -p places/disk-ahead-test",
77
+ "invocation_slug": "disk-ahead-test",
78
+ "invocation_name": "Disk Ahead Test",
79
+ "assertions": [
80
+ {
81
+ "type": "stdout_contains",
82
+ "pattern": "disk-ahead",
83
+ "description": "Skill identifies the disk-ahead state"
84
+ },
85
+ {
86
+ "type": "stdout_contains",
87
+ "pattern": "STOP",
88
+ "description": "Skill STOPs on disk-ahead"
89
+ },
90
+ {
91
+ "type": "exit_nonzero",
92
+ "description": "Skill exits non-zero on disk-ahead (not a clean enrollment)"
93
+ }
94
+ ],
95
+ "teardown": "rmdir places/disk-ahead-test 2>/dev/null || true"
96
+ },
97
+ "idempotency_test": {
98
+ "description": "Running rdc:onramp twice for already-enrolled should produce zero new writes",
99
+ "note": "Under RDC_TEST=1 this is verified by checking that [RDC_TEST] skipping markers appear (not real insert calls) and the checklist reports already-enrolled"
100
+ }
101
+ }
@@ -1,12 +1,12 @@
1
- {
2
- "manifest_version": 1,
3
- "skill": "rdc:env",
4
- "description": "Environment status is read-only and reports installed version.",
5
- "fixture": { "prompt": "rdc:env status", "env": { "RDC_\u0054EST": "1" }, "slow": false },
6
- "assertions": { "exit_code": 0, "stdout_contains": ["Environment"] },
7
- "acceptance": {
8
- "output_contains": ["version", "status"],
9
- "output_not_contains": ["force", "delete environment"]
10
- },
11
- "teardown": { "reset_branch": true }
12
- }
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:env",
4
+ "description": "Environment status is read-only and reports installed version.",
5
+ "fixture": { "prompt": "rdc:env status", "env": { "RDC_\u0054EST": "1" }, "slow": false },
6
+ "assertions": { "exit_code": 0, "stdout_contains": ["Environment"] },
7
+ "acceptance": {
8
+ "output_contains": ["version", "status"],
9
+ "output_not_contains": ["force", "delete environment"]
10
+ },
11
+ "teardown": { "reset_branch": true }
12
+ }
@@ -1,12 +1,12 @@
1
- {
2
- "manifest_version": 1,
3
- "skill": "rdc:new-model",
4
- "description": "New-model registration begins with the canonical gate.",
5
- "fixture": { "prompt": "rdc:new-model example-model", "env": { "RDC_\u0054EST": "1" }, "slow": true },
6
- "assertions": { "exit_code": 0, "stdout_contains": ["New Model"] },
7
- "acceptance": {
8
- "output_contains": ["canonical", "registration"],
9
- "output_not_contains": ["raw insert", "skip gate"]
10
- },
11
- "teardown": { "reset_branch": true }
12
- }
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:new-model",
4
+ "description": "New-model registration begins with the canonical gate.",
5
+ "fixture": { "prompt": "rdc:new-model example-model", "env": { "RDC_\u0054EST": "1" }, "slow": true },
6
+ "assertions": { "exit_code": 0, "stdout_contains": ["New Model"] },
7
+ "acceptance": {
8
+ "output_contains": ["canonical", "registration"],
9
+ "output_not_contains": ["raw insert", "skip gate"]
10
+ },
11
+ "teardown": { "reset_branch": true }
12
+ }
@@ -1,29 +1,29 @@
1
- {
2
- "manifest_version": 1,
3
- "skill": "rdc:refactor",
4
- "description": "Refactor preserves evidence and isolates all dispatched writers.",
5
- "fixture": {
6
- "prompt": "rdc:refactor hook-scope --takeover \"corrective consolidation\"",
7
- "env": { "RDC_\u0054EST": "1" },
8
- "slow": true
9
- },
10
- "assertions": {
11
- "exit_code": 0,
12
- "commits_made": { "min": 0 },
13
- "stdout_contains": ["RDC Refactor"]
14
- },
15
- "acceptance": {
16
- "output_contains": [
17
- "consolidate_work_items_into_epic",
18
- "unique leased worktree",
19
- "collaboration manifest",
20
- "validator"
21
- ],
22
- "output_not_contains": [
23
- "raw update",
24
- "shared working directory",
25
- "archive all"
26
- ]
27
- },
28
- "teardown": { "reset_branch": true }
29
- }
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:refactor",
4
+ "description": "Refactor preserves evidence and isolates all dispatched writers.",
5
+ "fixture": {
6
+ "prompt": "rdc:refactor hook-scope --takeover \"corrective consolidation\"",
7
+ "env": { "RDC_\u0054EST": "1" },
8
+ "slow": true
9
+ },
10
+ "assertions": {
11
+ "exit_code": 0,
12
+ "commits_made": { "min": 0 },
13
+ "stdout_contains": ["RDC Refactor"]
14
+ },
15
+ "acceptance": {
16
+ "output_contains": [
17
+ "consolidate_work_items_into_epic",
18
+ "unique leased worktree",
19
+ "collaboration manifest",
20
+ "validator"
21
+ ],
22
+ "output_not_contains": [
23
+ "raw update",
24
+ "shared working directory",
25
+ "archive all"
26
+ ]
27
+ },
28
+ "teardown": { "reset_branch": true }
29
+ }
@@ -1,29 +1,29 @@
1
- {
2
- "manifest_version": 1,
3
- "skill": "rdc:regen-media",
4
- "description": "Regen Media uses local keyless Codex gpt-image-2 as the primary image-generation path and avoids live generation under RDC_TEST.",
5
- "fixture": {
6
- "prompt": "rdc:regen-media generate a 2048x1152 homepage hero image",
7
- "env": { "RDC_TEST": "1" }
8
- },
9
- "assertions": {
10
- "exit_code": 0,
11
- "commits_made": { "min": 0 },
12
- "stdout_contains": ["image_gen", "gpt-image-2"]
13
- },
14
- "acceptance": {
15
- "output_contains": [
16
- "image_gen",
17
- "gpt-image-2",
18
- "--enable image_generation",
19
- "RDC_TEST"
20
- ],
21
- "output_not_contains": [
22
- "OPENAI_API_KEY=",
23
- "generate_gpt_image is the default",
24
- "upload completed",
25
- "raw MCP"
26
- ]
27
- },
28
- "teardown": { "reset_branch": true }
29
- }
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:regen-media",
4
+ "description": "Regen Media uses local keyless Codex gpt-image-2 as the primary image-generation path and avoids live generation under RDC_TEST.",
5
+ "fixture": {
6
+ "prompt": "rdc:regen-media generate a 2048x1152 homepage hero image",
7
+ "env": { "RDC_TEST": "1" }
8
+ },
9
+ "assertions": {
10
+ "exit_code": 0,
11
+ "commits_made": { "min": 0 },
12
+ "stdout_contains": ["image_gen", "gpt-image-2"]
13
+ },
14
+ "acceptance": {
15
+ "output_contains": [
16
+ "image_gen",
17
+ "gpt-image-2",
18
+ "--enable image_generation",
19
+ "RDC_TEST"
20
+ ],
21
+ "output_not_contains": [
22
+ "OPENAI_API_KEY=",
23
+ "generate_gpt_image is the default",
24
+ "upload completed",
25
+ "raw MCP"
26
+ ]
27
+ },
28
+ "teardown": { "reset_branch": true }
29
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: watch
3
- description: "Usage `rdc:watch`Initialize a live session-log viewer and report its path; open it only during attended, non-test use. Zero infrastructure — pure filesystem + static HTML."
3
+ description: rdc:watch () open a live session-log viewer and report its path
4
4
  ---
5
5
 
6
6
  > **⚠️ OUTPUT CONTRACT (READ FIRST):** `guides/output-contract.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: workitems
3
- description: "Usage `rdc:workitems [add|done|status|list|query]`Manual work item CRUD outside the normal build flow: add to backlog, mark done, update status, list open epics, query by label."
3
+ description: rdc:workitems ([subcommand])create, update and query work items directly
4
4
  ---
5
5
 
6
6
  > **⚠️ OUTPUT CONTRACT (READ FIRST):** `guides/output-contract.md`
@@ -228,10 +228,23 @@ try {
228
228
  // the user installed.
229
229
 
230
230
  {
231
- const pack = spawnSync('npm', ['pack', '--dry-run'], {
231
+ // `--json`, and loglevel forced.
232
+ //
233
+ // This read the human file listing, which npm prints at `notice` level. Run
234
+ // under `npm run --silent`, npm exports npm_config_loglevel=silent to every
235
+ // child, the listing vanishes, and the assertion reports "clauth-plugin.json
236
+ // must be present in the published tarball" — a packaging failure that is not
237
+ // happening. Measured 2026-08-29: PASS standalone, FAIL under --silent, with
238
+ // the file present in the tarball both times.
239
+ //
240
+ // A test whose verdict depends on the verbosity of the command that invoked
241
+ // it is a test that will eventually accuse the wrong thing. `--json` is a
242
+ // contract; the file listing is output formatting.
243
+ const pack = spawnSync('npm', ['pack', '--dry-run', '--json'], {
232
244
  cwd: REPO_ROOT,
233
245
  encoding: 'utf8',
234
246
  shell: process.platform === 'win32',
247
+ env: { ...process.env, npm_config_loglevel: 'notice' },
235
248
  });
236
249
  assert.equal(pack.status, 0, `npm pack --dry-run failed:\n${pack.stdout}\n${pack.stderr}`);
237
250
  const packOutput = `${pack.stdout}\n${pack.stderr}`;
@@ -40,8 +40,8 @@ assert.match(docs.readme, /Nineteen[\s\S]*\/rdc:\*` command shorthands/i, 'READM
40
40
  assert.match(docs.readme, /Use `rdc_skill_list` for the authoritative live catalog/, 'README should point callers to live MCP catalog');
41
41
  assert.doesNotMatch(docs.readme, /All user-invocable skills become available as slash commands/, 'README must not imply all MCP skills are slash commands');
42
42
  assert.doesNotMatch(docs.readme, /29 skills organized into 6 categories/, 'README must not carry stale category count');
43
- assert.match(docs.commandHelp, /menu of all MCP skills/, 'command help should refer to MCP skill catalog');
44
- assert.match(docs.skillHelp, /Show all MCP skills/, 'skill help should refer to MCP skill catalog');
43
+ assert.match(docs.commandHelp, /all MCP skills/, 'command help should refer to MCP skill catalog');
44
+ assert.match(docs.skillHelp, /all MCP skills/, 'skill help should refer to MCP skill catalog');
45
45
  assert.match(docs.skillHelp, /manifest-driven/i, 'skill help should be manifest-driven');
46
46
  assert.match(docs.commandHelp, /manifest-driven/i, 'command help should be manifest-driven');
47
47
  assert.doesNotMatch(docs.commandHelp, /Print the full usage menu below verbatim/, 'command help must not use stale static menu wording');
@@ -169,6 +169,60 @@ function runHook(payload, extraEnv = {}) {
169
169
  }
170
170
  }
171
171
 
172
+ // ---------------------------------------------------------------------------
173
+ // 4. The message must be READ before it is judged.
174
+ //
175
+ // extractCommitMessage used to fall back to the WHOLE COMMAND when there was no
176
+ // -m. CONVENTIONAL_TYPES is anchored at ^, so a heredoc commit whose subject was
177
+ // a valid `fix(scope): …` could never match — the tested string began with
178
+ // `( cd … && git add … && git commit -q -F -`. Measured 2026-08-29: this hook
179
+ // blocked a commit whose message DID begin with `fix(guards):` and reported
180
+ // "no conventional commit type", which was false.
181
+ //
182
+ // A heredoc is how every multi-paragraph commit in this fleet is authored, so
183
+ // the single path the gate made unusable was the correct one. The load-bearing
184
+ // half of this test is the NEGATIVE cases: reading the message must not become
185
+ // a way to pass without one.
186
+ {
187
+ const { extractCommitMessage } = require(HOOK);
188
+ const CONVENTIONAL = /^(feat|fix|chore|refactor|test|docs|style|perf|ci|build|revert)(\(.+\))?:/i;
189
+ const UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
190
+ const verdict = (cmd) => {
191
+ const { message, readable } = extractCommitMessage(cmd);
192
+ if (!readable) return 'unreadable';
193
+ return CONVENTIONAL.test(message.trim()) || UUID.test(message) ? 'pass' : 'block';
194
+ };
195
+
196
+ const realBlockedCommand = `( cd "C:/Dev/lifeai-env.wt/guard-remedy" && git add hooks/lib/guard-rules.mjs && git commit -q -F - <<'EOF'
197
+ fix(guards): rtp-steering-grep counted the pipeline next command as a search path
198
+
199
+ A multi-paragraph body, which is the entire reason -F is being used.
200
+ EOF
201
+ )`;
202
+
203
+ for (const [name, cmd, want] of [
204
+ ['heredoc with a conventional subject passes', realBlockedCommand, 'pass'],
205
+ ['heredoc <<-EOF passes', "git commit -F - <<-EOF\nfix(a): b\nEOF", 'pass'],
206
+ ['heredoc with a quoted delimiter passes', 'git commit -F - <<"MSG"\nfix(a): b\nMSG', 'pass'],
207
+ ['heredoc carrying only a UUID passes', "git commit -F - <<'EOF'\nwip\n\nWork-Item: f27ff5fa-0000-4000-8000-000000000000\nEOF", 'pass'],
208
+ ['-m still passes', 'git commit -m "fix(x): y"', 'pass'],
209
+ // Negative controls — reading the message is not a bypass.
210
+ ['heredoc without a type or UUID still blocks', "git commit -F - <<'EOF'\nrandom words\nEOF", 'block'],
211
+ ['a bare commit still blocks', 'git commit', 'block'],
212
+ // Honest about what it cannot see, rather than calling it absent.
213
+ ['a real stdin pipe reports unreadable', 'cat msg.txt | git commit -q -F -', 'unreadable'],
214
+ ]) {
215
+ assert(`extract: ${name}`, verdict(cmd) === want, `got ${verdict(cmd)}, want ${want}`);
216
+ }
217
+
218
+ // -F <path> reads the message off disk.
219
+ const msgFile = join(mkdtempSync(join(tmpdir(), 'wi-msg-')), 'COMMIT_EDITMSG');
220
+ writeFileSync(msgFile, 'refactor(core): tidy\n\nbody\n');
221
+ assert('extract: -F <file> with a type passes', verdict(`git commit -F ${msgFile}`) === 'pass');
222
+ writeFileSync(msgFile, 'no type here\n');
223
+ assert('extract: -F <file> without a type still blocks', verdict(`git commit -F ${msgFile}`) === 'block');
224
+ }
225
+
172
226
  // ---------------------------------------------------------------------------
173
227
  if (failures.length > 0) {
174
228
  console.error('\ncommit-capture hook tests — FAIL\n');
@@ -1,18 +0,0 @@
1
- // Local PM2 process definition for rdc-skills-mcp — mirrors regen-media-local
2
- // exactly (local PM2 process, tunneled via cloudflared, never on Vultr).
3
- module.exports = {
4
- apps: [
5
- {
6
- name: "rdc-skills-mcp",
7
- script: "bin/rdc-skills-mcp.mjs",
8
- cwd: __dirname,
9
- interpreter: "node",
10
- env: {
11
- PORT: "3110",
12
- },
13
- autorestart: true,
14
- max_restarts: 10,
15
- restart_delay: 5000,
16
- },
17
- ],
18
- };