@lifeaitools/rdc-skills 0.33.0 → 0.34.0

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,4 +1,4 @@
1
- interface:
2
- display_name: "Behavior Audit"
3
- short_description: "Audit Claude and Codex behavior against shared rules."
4
- default_prompt: "Run a behavior audit for the last seven days and write the evidence bundle to a report directory."
1
+ interface:
2
+ display_name: "Behavior Audit"
3
+ short_description: "Audit Claude and Codex behavior against shared rules."
4
+ default_prompt: "Run a behavior audit for the last seven days and write the evidence bundle to a report directory."
@@ -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
+ }
@@ -0,0 +1,256 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `scripts/postinstall.js` self-registers `clauth-plugin.json` with the local
4
+ * clauth supervisor — and must NEVER be able to fail an install.
5
+ *
6
+ * The whole point of the file is its failure behaviour, so that is what is
7
+ * asserted: absent clauth, non-zero register, a spawn that throws, and a
8
+ * missing manifest all exit 0 with a printed hint. Also asserted is the path
9
+ * anchor — during `npm i -g` the cwd is not the package root, so a
10
+ * cwd-relative manifest path would resolve to nothing and silently no-op.
11
+ *
12
+ * Registration is STUBBED, never really invoked: the live managed-plugin root
13
+ * (%APPDATA%/clauth/supervisor/managed-plugins) holds real registered plugins
14
+ * that the running daemon reads, and a test has no business writing there.
15
+ */
16
+ import assert from 'node:assert/strict';
17
+ import { spawnSync } from 'node:child_process';
18
+ import { createRequire } from 'node:module';
19
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
20
+ import { tmpdir } from 'node:os';
21
+ import { dirname, join, resolve } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const REPO_ROOT = resolve(__dirname, '..');
26
+ const script = join(REPO_ROOT, 'scripts', 'postinstall.js');
27
+ const require = createRequire(import.meta.url);
28
+
29
+ // ---------------------------------------------------------------- 0. wiring
30
+
31
+ const syntax = spawnSync(process.execPath, ['--check', script], { encoding: 'utf8' });
32
+ assert.equal(syntax.status, 0, syntax.stderr);
33
+
34
+ const packageJson = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8'));
35
+ assert.equal(
36
+ packageJson.scripts.postinstall,
37
+ 'node scripts/postinstall.js',
38
+ 'package.json must run the postinstall registrar on install',
39
+ );
40
+ assert.equal(
41
+ existsSync(join(REPO_ROOT, 'clauth-plugin.json')),
42
+ true,
43
+ 'the manifest the postinstall registers must exist in the repo',
44
+ );
45
+
46
+ const postinstall = require(script);
47
+
48
+ /** A spawnSync stub that records calls and replays canned results. */
49
+ function stubSpawn(results) {
50
+ const calls = [];
51
+ const queue = [...results];
52
+ const spawn = (command, args, options) => {
53
+ calls.push({ command, args, options });
54
+ const next = queue.shift();
55
+ if (typeof next === 'function') return next();
56
+ return next ?? { status: 0, stdout: '', stderr: '' };
57
+ };
58
+ return { spawn, calls };
59
+ }
60
+
61
+ function collectLog() {
62
+ const lines = [];
63
+ return { log: (line) => lines.push(String(line)), lines };
64
+ }
65
+
66
+ /**
67
+ * A child env whose ONLY PATH entry is `dir`, so nothing named `clauth` can
68
+ * resolve. Windows env vars are case-insensitive, so every existing spelling of
69
+ * PATH has to be dropped first or the original one wins non-deterministically.
70
+ */
71
+ function envWithOnlyPath(dir) {
72
+ const env = {};
73
+ for (const [key, value] of Object.entries(process.env)) {
74
+ if (/^path$/i.test(key) || key === postinstall.SKIP_ENV) continue;
75
+ env[key] = value;
76
+ }
77
+ env.PATH = dir;
78
+ return env;
79
+ }
80
+
81
+ // ------------------------------------------- 1. clauth absent -> exit 0 + hint
82
+ //
83
+ // Run the real script as a child with PATH stripped to an empty directory, so
84
+ // nothing named `clauth` can resolve. This is the end-to-end form of the
85
+ // contract: a box without clauth still gets a successful install.
86
+
87
+ const emptyPathDir = mkdtempSync(join(tmpdir(), 'rdc-postinstall-nopath-'));
88
+ try {
89
+ const run = spawnSync(process.execPath, [script], {
90
+ cwd: REPO_ROOT,
91
+ encoding: 'utf8',
92
+ env: envWithOnlyPath(emptyPathDir),
93
+ });
94
+ assert.equal(run.status, 0, `postinstall must exit 0 without clauth on PATH:\n${run.stdout}\n${run.stderr}`);
95
+ assert.match(
96
+ run.stdout,
97
+ /clauth not found/,
98
+ `expected a "clauth not found" hint, got:\n${run.stdout}`,
99
+ );
100
+ assert.match(
101
+ run.stdout,
102
+ /clauth plugin register/,
103
+ 'the hint must carry the manual command so a human can finish registration',
104
+ );
105
+ } finally {
106
+ rmSync(emptyPathDir, { recursive: true, force: true });
107
+ }
108
+
109
+ // --------------------------------- 2. clauth present -> register invoked right
110
+
111
+ {
112
+ const { spawn, calls } = stubSpawn([
113
+ { status: 0, stdout: '0.33.0\n', stderr: '' }, // --version probe
114
+ { status: 0, stdout: 'registered\n', stderr: '' }, // plugin register
115
+ ]);
116
+ const { log, lines } = collectLog();
117
+ const result = postinstall.register({ spawn, log });
118
+
119
+ assert.equal(result.outcome, 'registered');
120
+ assert.equal(calls.length, 2, 'expected a --version probe followed by the register call');
121
+ assert.equal(calls[0].command, 'clauth');
122
+ assert.deepEqual(calls[0].args.map(unquote), ['--version']);
123
+
124
+ assert.equal(calls[1].command, 'clauth');
125
+ assert.deepEqual(
126
+ calls[1].args.map(unquote),
127
+ ['plugin', 'register', join(REPO_ROOT, 'clauth-plugin.json')],
128
+ 'register must be called as `clauth plugin register <package-root>/clauth-plugin.json`',
129
+ );
130
+ assert.ok(calls[1].options.timeout > 0, 'the register call must be time-bounded');
131
+ assert.match(lines.join('\n'), /registered/);
132
+ }
133
+
134
+ // ------------------------- 3. non-zero register / throwing spawn -> exit 0 + hint
135
+
136
+ {
137
+ const { spawn } = stubSpawn([
138
+ { status: 0, stdout: '0.33.0\n', stderr: '' },
139
+ { status: 1, stdout: '', stderr: 'manifest rejected: bad schema\n' },
140
+ ]);
141
+ const { log, lines } = collectLog();
142
+ const result = postinstall.register({ spawn, log });
143
+
144
+ assert.equal(result.outcome, 'register-failed', 'a non-zero register must not throw');
145
+ assert.match(lines.join('\n'), /clauth plugin register failed/);
146
+ assert.match(lines.join('\n'), /manifest rejected: bad schema/, 'the hint should surface why');
147
+ assert.match(lines.join('\n'), /retry with: clauth plugin register/);
148
+ }
149
+
150
+ {
151
+ // spawn itself blowing up (EPERM, locked binary, AV interference) is still exit 0.
152
+ const { spawn } = stubSpawn([
153
+ { status: 0, stdout: '0.33.0\n', stderr: '' },
154
+ () => {
155
+ throw new Error('EPERM: operation not permitted');
156
+ },
157
+ ]);
158
+ const { log, lines } = collectLog();
159
+ const result = postinstall.register({ spawn, log });
160
+
161
+ assert.equal(result.outcome, 'spawn-failed');
162
+ assert.match(lines.join('\n'), /EPERM/);
163
+ }
164
+
165
+ {
166
+ // clauth on PATH but broken (`--version` non-zero) reads as "not available".
167
+ const { spawn, calls } = stubSpawn([{ status: 9009, stdout: '', stderr: 'not recognized' }]);
168
+ const { log, lines } = collectLog();
169
+ const result = postinstall.register({ spawn, log });
170
+
171
+ assert.equal(result.outcome, 'no-clauth');
172
+ assert.equal(calls.length, 1, 'a failed probe must not go on to attempt registration');
173
+ assert.match(lines.join('\n'), /clauth not found/);
174
+ }
175
+
176
+ {
177
+ // A package root with no manifest is a hint, not a crash.
178
+ const bare = mkdtempSync(join(tmpdir(), 'rdc-postinstall-bare-'));
179
+ try {
180
+ const { spawn, calls } = stubSpawn([]);
181
+ const { log, lines } = collectLog();
182
+ const result = postinstall.register({ packageRoot: bare, spawn, log });
183
+
184
+ assert.equal(result.outcome, 'no-manifest');
185
+ assert.equal(calls.length, 0, 'a missing manifest must not spawn anything');
186
+ assert.match(lines.join('\n'), /not found/);
187
+ } finally {
188
+ rmSync(bare, { recursive: true, force: true });
189
+ }
190
+ }
191
+
192
+ // ----------------------------------- 4. the manifest path is package-anchored
193
+ //
194
+ // `npm i -g` runs the postinstall from an arbitrary cwd. Anything cwd-relative
195
+ // would resolve to a path that does not exist and register nothing at all.
196
+
197
+ {
198
+ assert.equal(
199
+ postinstall.manifestPath(),
200
+ join(REPO_ROOT, 'clauth-plugin.json'),
201
+ 'the default manifest path must be the package root, not the cwd',
202
+ );
203
+
204
+ const foreignCwd = mkdtempSync(join(tmpdir(), 'rdc-postinstall-cwd-'));
205
+ try {
206
+ const run = spawnSync(process.execPath, [script], {
207
+ cwd: foreignCwd, // deliberately NOT the package root
208
+ encoding: 'utf8',
209
+ env: envWithOnlyPath(foreignCwd),
210
+ });
211
+ assert.equal(run.status, 0, `${run.stdout}\n${run.stderr}`);
212
+ assert.ok(
213
+ run.stdout.includes(join(REPO_ROOT, 'clauth-plugin.json')),
214
+ `hint must name the package-root manifest, not a cwd-relative one:\n${run.stdout}`,
215
+ );
216
+ assert.ok(
217
+ !run.stdout.includes(join(foreignCwd, 'clauth-plugin.json')),
218
+ 'the manifest path must never be resolved against the caller cwd',
219
+ );
220
+ } finally {
221
+ rmSync(foreignCwd, { recursive: true, force: true });
222
+ }
223
+ }
224
+
225
+ // --------------------------------- 5. the manifest actually ships in the tarball
226
+ //
227
+ // Self-registration is worthless if `clauth-plugin.json` is not in the package
228
+ // the user installed.
229
+
230
+ {
231
+ const pack = spawnSync('npm', ['pack', '--dry-run'], {
232
+ cwd: REPO_ROOT,
233
+ encoding: 'utf8',
234
+ shell: process.platform === 'win32',
235
+ });
236
+ assert.equal(pack.status, 0, `npm pack --dry-run failed:\n${pack.stdout}\n${pack.stderr}`);
237
+ const packOutput = `${pack.stdout}\n${pack.stderr}`;
238
+ assert.match(
239
+ packOutput,
240
+ /clauth-plugin\.json/,
241
+ 'clauth-plugin.json must be present in the published tarball',
242
+ );
243
+ assert.match(
244
+ packOutput,
245
+ /scripts\/postinstall\.js/,
246
+ 'scripts/postinstall.js must be present in the published tarball',
247
+ );
248
+ }
249
+
250
+ /** Strip the Windows shell quoting the script applies to spawn args. */
251
+ function unquote(arg) {
252
+ const s = String(arg);
253
+ return s.startsWith('"') && s.endsWith('"') ? s.slice(1, -1).replace(/\\"/g, '"') : s;
254
+ }
255
+
256
+ console.log('clauth plugin postinstall tests — PASS');