@lifeaitools/rdc-skills 0.9.32 → 0.9.34

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 (40) hide show
  1. package/.claude-plugin/plugin.json +25 -2
  2. package/MANIFEST.md +4 -0
  3. package/commands/build.md +2 -2
  4. package/commands/fixit.md +14 -2
  5. package/commands/workitems.md +6 -1
  6. package/guides/agent-bootstrap.md +71 -8
  7. package/guides/agents/backend.md +2 -2
  8. package/guides/agents/data.md +1 -1
  9. package/guides/agents/frontend.md +1 -1
  10. package/guides/agents/setup.md +4 -2
  11. package/guides/engineering-behavior.md +43 -0
  12. package/hooks/foreground-process-gate.js +109 -0
  13. package/hooks/hook-logger.js +25 -0
  14. package/hooks/run-hidden-hook.ps1 +47 -0
  15. package/hooks/work-item-exit-gate.js +297 -0
  16. package/package.json +3 -3
  17. package/rules/work-items-rpc.md +56 -7
  18. package/scripts/install-rdc-skills.js +75 -9
  19. package/scripts/install.ps1 +17 -11
  20. package/scripts/self-test.mjs +14 -0
  21. package/skills/build/SKILL.md +13 -9
  22. package/skills/co-develop/SKILL.md +182 -0
  23. package/skills/collab/SKILL.md +1 -1
  24. package/skills/deploy/SKILL.md +1 -1
  25. package/skills/design/SKILL.md +3 -3
  26. package/skills/fixit/SKILL.md +19 -5
  27. package/skills/fs-mcp/SKILL.md +131 -0
  28. package/skills/handoff/SKILL.md +1 -1
  29. package/skills/help/SKILL.md +4 -2
  30. package/skills/overnight/SKILL.md +3 -3
  31. package/skills/plan/SKILL.md +4 -3
  32. package/skills/preplan/SKILL.md +1 -1
  33. package/skills/prototype/SKILL.md +1 -1
  34. package/skills/release/SKILL.md +2 -2
  35. package/skills/report/SKILL.md +1 -1
  36. package/skills/review/SKILL.md +5 -3
  37. package/skills/self-test/SKILL.md +1 -1
  38. package/skills/status/SKILL.md +3 -1
  39. package/skills/watch/SKILL.md +1 -1
  40. package/skills/workitems/SKILL.md +7 -2
@@ -1,11 +1,34 @@
1
1
  {
2
2
  "name": "rdc",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
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",
7
7
  "email": "support@lifeai.tools"
8
8
  },
9
9
  "homepage": "https://github.com/LIFEAI/rdc-skills",
10
- "repository": "https://github.com/LIFEAI/rdc-skills"
10
+ "repository": "https://github.com/LIFEAI/rdc-skills",
11
+ "skills": [
12
+ "build",
13
+ "co-develop",
14
+ "collab",
15
+ "deploy",
16
+ "design",
17
+ "fixit",
18
+ "fs-mcp",
19
+ "handoff",
20
+ "help",
21
+ "overnight",
22
+ "plan",
23
+ "preplan",
24
+ "prototype",
25
+ "release",
26
+ "report",
27
+ "review",
28
+ "self-test",
29
+ "status",
30
+ "terminal-config",
31
+ "watch",
32
+ "workitems"
33
+ ]
11
34
  }
package/MANIFEST.md CHANGED
@@ -47,6 +47,7 @@ All skills have been converted from project-specific to generic/portable:
47
47
  ├── fixit/SKILL.md
48
48
  ├── status/SKILL.md
49
49
  ├── report/SKILL.md
50
+ ├── co-develop/SKILL.md [peer-aware Claude/Codex co-development]
50
51
  ├── collab/SKILL.md [claude.ai ↔ Claude Code relay]
51
52
  ├── handoff/SKILL.md
52
53
  ├── prototype/SKILL.md
@@ -92,6 +93,9 @@ All skills have been converted from project-specific to generic/portable:
92
93
  ### Quality (1)
93
94
  - rdc:self-test — static lint (tier1) + smoke tests (tier2)
94
95
 
96
+ ### Collaboration (1)
97
+ - rdc:co-develop — peer-aware Claude/Codex co-development over clauth
98
+
95
99
  ### Agent Guides (10, in `guides/agents/`) — [agent-only — dispatched by rdc:build, not user-invocable]
96
100
  - frontend — React, UI, Tailwind
97
101
  - backend — API, database, auth
package/commands/build.md CHANGED
@@ -132,7 +132,7 @@ Read the task title and description, then:
132
132
  9. **As agents complete:**
133
133
  - Verify commit landed on the development branch
134
134
  - Push to origin *(skip if `$RDC_TEST=1` — echo `[RDC_TEST] skipping git push` instead)*
135
- - Set work item to `done` with notes
135
+ - Ensure the agent submitted `implementation_report.codeflow_post`, then set the work item to `review`; the validator closes `done`
136
136
  - Continue to next wave
137
137
 
138
138
  **If an agent fails:**
@@ -142,7 +142,7 @@ Read the task title and description, then:
142
142
  BUILD_STATUS: { wave, tasks_done, tasks_failed, commits, escalated: true }
143
143
  ```
144
144
 
145
- 10. **Final verification gate (mandatory — before marking epic done):**
145
+ 10. **Final verification gate (mandatory — before marking work or epic done):**
146
146
  Dispatch the verify agent (see `guides/agents/verify.md`) across every package/app touched in this build.
147
147
  The Iron Law: **NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE.**
148
148
  - Run `npx vitest run --dir <pkg>` fresh for each touched package
package/commands/fixit.md CHANGED
@@ -87,11 +87,23 @@ else
87
87
  fi
88
88
  ```
89
89
 
90
- ### 6. Close and clean up
90
+ ### 6. Report, review, close, and clean up
91
91
 
92
92
  ```sql
93
+ SELECT submit_implementation_report('<id>'::uuid,
94
+ '{"tldr":"<one sentence>","assumptions":[],"deviations":[],"uncertainty":[],"detail":"<what was fixed>","flags":[],"transactional":false,"memory_records":[],"codeflow_post":{"agent_session_id":"<agent-session-id>","summary":"<what changed and why>","files_changed":["<path>"],"verification":["<command/evidence>"],"commit":"<hash optional>"}}'::jsonb
95
+ );
96
+
97
+ SELECT update_work_item_status('<id>'::uuid, 'review',
98
+ '["Fixed via rdc:fixit; ready for validation"]'::jsonb,
99
+ '<agent-session-id>',
100
+ 'agent'
101
+ );
102
+
93
103
  SELECT update_work_item_status('<id>'::uuid, 'done',
94
- '["Fixed via rdc:fixit"]'::jsonb
104
+ '["Validator verified rdc:fixit report, CodeFlow post, and checklist evidence"]'::jsonb,
105
+ '<validator-session-id>',
106
+ 'validator'
95
107
  );
96
108
  ```
97
109
 
@@ -66,10 +66,15 @@ Est: <hours>',
66
66
 
67
67
  ```sql
68
68
  SELECT update_work_item_status('<uuid>'::uuid, 'in_progress');
69
- SELECT update_work_item_status('<uuid>'::uuid, 'done', '["What was completed"]'::jsonb);
69
+ SELECT update_work_item_status('<uuid>'::uuid, 'review', '["Implementation complete; ready for validator"]'::jsonb, '<agent-session-id>', 'agent');
70
+ SELECT update_work_item_status('<uuid>'::uuid, 'done', '["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb, '<validator-session-id>', 'validator');
70
71
  SELECT update_work_item_status('<uuid>'::uuid, 'blocked', '["Why it is blocked"]'::jsonb);
71
72
  ```
72
73
 
74
+ Non-epic `done` is a validator-only close and requires an existing
75
+ `implementation_report.codeflow_post`, checked required checklist evidence, and
76
+ originating-agent tick audit.
77
+
73
78
  ## Read Tasks in an Epic
74
79
 
75
80
  ```sql
@@ -10,6 +10,10 @@ You are a subagent dispatched by the rdc:build supervisor. You have a specific
10
10
  scope (files, package, feature) that will be in your prompt. Stay in that scope.
11
11
  NEVER modify files outside it.
12
12
 
13
+ Read `guides/engineering-behavior.md` next when it is available. It defines the
14
+ RDC implementation posture for assumptions, minimal changes, surgical scope,
15
+ verification evidence, and escalation.
16
+
13
17
  ---
14
18
 
15
19
  ## Credentials — Daemon Access Pattern
@@ -86,6 +90,18 @@ Never run `pnpm build` or equivalent full builds locally — they consume excess
86
90
  Type-check only: `npx tsc --noEmit --project <path>/tsconfig.json`
87
91
  Run tests only for modified packages: modify tests in isolation, not whole suite.
88
92
 
93
+ ### No Foreground Windows
94
+
95
+ Agent-launched processes must not steal focus. This is a hard local-operator
96
+ rule, not a preference.
97
+
98
+ - Playwright must run headless. Do not use `--headed`, `--ui`, `codegen`, `open`, `show-report`, or `PWDEBUG=1` in agent sessions.
99
+ - Use list/dot/json reporters and saved trace/report artifacts instead of opening the Playwright UI.
100
+ - PowerShell helpers must use `-WindowStyle Hidden -NonInteractive`, or a hidden wrapper.
101
+ - `Start-Process` must include `-WindowStyle Hidden` or `-WindowStyle Minimized`.
102
+ - `cmd /c start` must use `/min` for intentionally visible tools or `/b` for background work.
103
+ - Node/cmd/ps1 helpers launched by hooks must go through the RDC hidden hook runner.
104
+
89
105
  Check the project overlay for specific language, package manager, and build constraints.
90
106
 
91
107
  ---
@@ -183,36 +199,83 @@ If you discover that fixing your assigned task would also require changing files
183
199
 
184
200
  ---
185
201
 
186
- ## ⛔ Implementation Report Contract
202
+ ## ⛔ Implementation Report + CodeFlow Exit Contract
187
203
 
188
- Every agent MUST follow this protocol before closing any work item as `done`.
204
+ Every implementation agent MUST follow this protocol before moving a work item
205
+ to `review`. Agents do not close non-epic work as `done`; validators close it
206
+ after fresh verification.
189
207
 
190
208
  ### Step 1 — Tick checklist items as you complete them
191
209
 
192
210
  ```sql
193
- SELECT update_checklist_item('<work-item-id>'::uuid, 'item-id', true);
211
+ SELECT update_checklist_item(
212
+ '<work-item-id>'::uuid,
213
+ 'item-id',
214
+ true,
215
+ '<agent-session-id>',
216
+ 'agent',
217
+ 'rpc'
218
+ );
194
219
  ```
195
220
 
196
- Call this for each item AS you complete it — not all at once at the end.
221
+ Call this for each item AS you complete it — not all at once at the end. The
222
+ database records every tick in `work_item_checklist_events`. Supervisor and
223
+ validator re-ticks are rejected by the exit gate.
197
224
 
198
225
  ### Step 2 — Submit implementation report BEFORE marking done
199
226
 
200
227
  ```sql
201
228
  SELECT submit_implementation_report(
202
229
  '<work-item-id>'::uuid,
203
- '{"tldr":"...","assumptions":[],"deviations":[],"uncertainty":[],"detail":"...","flags":[]}'::jsonb
230
+ '{
231
+ "tldr":"...",
232
+ "assumptions":[],
233
+ "deviations":[],
234
+ "uncertainty":[],
235
+ "detail":"...",
236
+ "flags":[],
237
+ "codeflow_post":{
238
+ "agent_session_id":"<agent-session-id>",
239
+ "summary":"...",
240
+ "files_changed":["path/to/file"],
241
+ "verification":["command or evidence"],
242
+ "commit":"<optional commit hash>"
243
+ }
244
+ }'::jsonb
204
245
  );
205
246
  ```
206
247
 
207
248
  Returns `{ flags_count, deviations_count, has_deviations }`. Include this signal in your `AGENT_COMPLETE` report.
208
249
 
209
- ### Step 3 — Mark done
250
+ ### Step 3 — Move to review
210
251
 
211
252
  ```sql
212
- SELECT update_work_item_status('<work-item-id>'::uuid, 'done');
253
+ SELECT update_work_item_status(
254
+ '<work-item-id>'::uuid,
255
+ 'review',
256
+ '["Implementation complete; ready for validator"]'::jsonb,
257
+ '<agent-session-id>',
258
+ 'agent'
259
+ );
260
+ ```
261
+
262
+ If the report or `codeflow_post` is missing, the database raises EXCEPTION.
263
+
264
+ ### Validator close — mark done only after fresh review
265
+
266
+ ```sql
267
+ SELECT update_work_item_status(
268
+ '<work-item-id>'::uuid,
269
+ 'done',
270
+ '["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb,
271
+ '<validator-session-id>',
272
+ 'validator'
273
+ );
213
274
  ```
214
275
 
215
- If any `required: true` checklist item is still unchecked, the DB raises EXCEPTION — fix it first.
276
+ If any `required: true` checklist item is still unchecked, was re-ticked by a
277
+ supervisor/validator, or was ticked by a different session than the originating
278
+ agent, the DB and PreToolUse hook reject the close.
216
279
 
217
280
  ### Supervisor workflow
218
281
 
@@ -57,8 +57,8 @@ SELECT insert_work_item(
57
57
  p_source := 'agent'
58
58
  );
59
59
 
60
- -- Update
61
- SELECT update_work_item_status('<uuid>'::uuid, 'done', '["What was done"]'::jsonb);
60
+ -- Implementation agents submit report + CodeFlow post, then move to review
61
+ SELECT update_work_item_status('<uuid>'::uuid, 'review', '["Implementation complete; ready for validator"]'::jsonb, '<agent-session-id>', 'agent');
62
62
  ```
63
63
 
64
64
  **NEVER write raw INSERT/UPDATE against work items.**
@@ -37,7 +37,7 @@ After `apply_migration`: always verify with queries.
37
37
  ```sql
38
38
  SELECT get_open_epics();
39
39
  SELECT insert_work_item(p_title := 'Task', p_priority := 'high', p_labels := ARRAY['data'], p_source := 'agent');
40
- SELECT update_work_item_status('<uuid>'::uuid, 'done');
40
+ SELECT update_work_item_status('<uuid>'::uuid, 'review', '["Implementation complete; ready for validator"]'::jsonb, '<agent-session-id>', 'agent');
41
41
  SELECT get_work_items_by_epic('<epic-uuid>'::uuid);
42
42
  ```
43
43
 
@@ -88,5 +88,5 @@ Never hardcode hex values in components. Always use CSS variables from the app's
88
88
  - NEVER overlap with other agents on the same files
89
89
  - NEVER modify files outside your assigned scope
90
90
  - After completing: commit with descriptive message, push *(skip push if `$RDC_TEST=1` — echo `[RDC_TEST] skipping git push` instead)*
91
- - Update work item to `done` via `update_work_item_status()`
91
+ - Submit `implementation_report.codeflow_post`, then update work item to `review` via `update_work_item_status(..., p_actor_role := 'agent')`; validators close `done`
92
92
  - Write tests FIRST — red → implement → green
@@ -142,7 +142,7 @@ Use `mcp__claude_ai_Supabase__execute_sql` — no `project_id` needed.
142
142
  ## Work Items
143
143
  SELECT get_open_epics();
144
144
  SELECT insert_work_item(p_title := '...', p_priority := 'high');
145
- SELECT update_work_item_status('<id>'::uuid, 'done');
145
+ SELECT update_work_item_status('<id>'::uuid, 'review', '["Implementation complete; ready for validator"]'::jsonb, '<agent-session-id>', 'agent');
146
146
  Create work items BEFORE starting work.
147
147
 
148
148
  ## Completion Report
@@ -206,12 +206,14 @@ agents, manages git, enforces hooks, and ships to production.
206
206
 
207
207
  | Capability | Tool |
208
208
  |-----------|------|
209
- | Read/write repo files | `fs_read`, `fs_write`, `fs_glob`, `fs_grep` |
209
+ | Read/write/import repo files | `fs_read`, `fs_write`, `fs_write_chunk`, `fs_ingest_url`, `fs_import_git_files`, `fs_glob`, `fs_grep` |
210
210
  | Query Supabase | Supabase MCP `execute_sql` |
211
211
  | GitHub operations | Github Proxy MCP |
212
212
  | Credentials | clauth MCP `clauth_get` |
213
213
  | Trigger Claude Code | `monkey_dispatch` MCP |
214
214
 
215
+ For filesystem decisions, load `rdc:fs-mcp`. It defines when to use direct FS writes, chunked writes, URL ingest, or GitHub-branch import into the dirty local monorepo.
216
+
215
217
  ## Two-Claude Relay
216
218
 
217
219
  Two channels to communicate with Claude Code:
@@ -0,0 +1,43 @@
1
+ # Engineering Behavior
2
+
3
+ Use this with `agent-bootstrap.md` for implementation and review work. These
4
+ rules adapt general coding-agent hygiene into the RDC work-item contract.
5
+
6
+ ## Before Editing
7
+
8
+ - State material assumptions in the work-item report; ask or block when the
9
+ ambiguity changes architecture, data shape, security, or user-visible scope.
10
+ - Prefer the smallest change that satisfies the assigned checklist rows.
11
+ - Do not add features, abstractions, configurability, or fallback behavior that
12
+ is not required by the work item.
13
+ - If a simpler path exists than the apparent request, report the tradeoff before
14
+ widening the implementation.
15
+
16
+ ## While Editing
17
+
18
+ - Stay inside the assigned files, package, route, or work-item boundary.
19
+ - Match the local style and contracts already in the touched files.
20
+ - Do not reformat, rename, or refactor adjacent code unless the checklist row
21
+ explicitly requires it.
22
+ - Clean up only the unused imports, variables, files, or branches created by
23
+ your own change.
24
+ - If existing code looks dead or wrong but is outside scope, list it as a
25
+ blocker or follow-up. Do not remove it.
26
+
27
+ ## Verification
28
+
29
+ - Every completed row needs evidence: test output, route probe, SQL result,
30
+ screenshot artifact, type-check output, CLI transcript, or reviewer citation.
31
+ - Finding an existing file is not evidence. Verify the required behavior.
32
+ - Tick each `decomp-*` and `test-*` checklist item immediately after proving
33
+ that exact behavior. Do not batch ticks at the end.
34
+ - Record assumptions, deviations, uncertainty, blockers, files changed, and
35
+ verification in `submit_implementation_report()` before moving to `review`.
36
+
37
+ ## Escalation
38
+
39
+ - Stop and report `BLOCKED` when the fix requires files outside scope, a broader
40
+ architectural choice, a missing credential, or a second repeated failure.
41
+ - In unattended mode, choose the most conservative valid path only when the
42
+ acceptance criteria remain unchanged; otherwise escalate through the advisor
43
+ path required by the active skill.
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PreToolUse hook — block focus-stealing foreground process launches.
4
+ */
5
+ 'use strict';
6
+
7
+ const hookLog = require('./hook-logger');
8
+
9
+ function readStdin() {
10
+ return new Promise((resolve) => {
11
+ let input = '';
12
+ process.stdin.setEncoding('utf8');
13
+ process.stdin.on('data', (chunk) => { input += chunk; });
14
+ process.stdin.on('end', () => resolve(input));
15
+ process.stdin.resume();
16
+ });
17
+ }
18
+
19
+ function block(message, details = {}) {
20
+ hookLog('foreground-process-gate', 'PreToolUse', 'block', details);
21
+ process.stdout.write(JSON.stringify({
22
+ systemMessage: `HARD BLOCK — Foreground process launch rejected.\n\n${message}`,
23
+ }));
24
+ process.exit(1);
25
+ }
26
+
27
+ function pass(details = {}) {
28
+ hookLog('foreground-process-gate', 'PreToolUse', 'pass', details);
29
+ process.exit(0);
30
+ }
31
+
32
+ function toolText(raw) {
33
+ if (typeof raw.tool_input?.command === 'string') return raw.tool_input.command;
34
+ if (typeof raw.tool_input === 'string') return raw.tool_input;
35
+ try { return JSON.stringify(raw.tool_input || raw); } catch { return ''; }
36
+ }
37
+
38
+ function hasHiddenIntent(command) {
39
+ return /-WindowStyle\s+Hidden/i.test(command) ||
40
+ /-WindowStyle\s+Minimized/i.test(command) ||
41
+ /windowsHide\s*:\s*true/i.test(command) ||
42
+ /CreateNoWindow\s*=\s*\$?true/i.test(command) ||
43
+ /Start-Job\b/i.test(command) ||
44
+ /--background\b/i.test(command) ||
45
+ /\bHEADLESS\s*=\s*(1|true)\b/i.test(command) ||
46
+ /\bCI\s*=\s*(1|true)\b/i.test(command);
47
+ }
48
+
49
+ function checkPlaywright(command) {
50
+ if (!/\b(playwright|@playwright\/test)\b/i.test(command)) return;
51
+
52
+ if (/\bplaywright\s+(show-report|codegen|open)\b/i.test(command)) {
53
+ block(
54
+ 'Playwright report/codegen/open launches foreground UI. Use trace/report files as artifacts, or run a hidden/background smoke wrapper.',
55
+ { kind: 'playwright-ui' },
56
+ );
57
+ }
58
+
59
+ if (/(^|[\s;&|])(--headed|--ui|PWDEBUG\s*=\s*1|PWDEBUG\s*=\s*true)(?=$|[\s;&|])/i.test(command)) {
60
+ block(
61
+ 'Playwright must run headless in agent sessions. Remove `--headed`, `--ui`, and `PWDEBUG=1`; use `--reporter=list` or an artifact trace instead.',
62
+ { kind: 'playwright-headed' },
63
+ );
64
+ }
65
+ }
66
+
67
+ function checkPowerShell(command) {
68
+ if (!/\bStart-Process\b/i.test(command)) return;
69
+ if (hasHiddenIntent(command)) return;
70
+ block(
71
+ '`Start-Process` must include `-WindowStyle Hidden` or `-WindowStyle Minimized` for agent-launched node/cmd/ps1/test processes.',
72
+ { kind: 'start-process' },
73
+ );
74
+ }
75
+
76
+ function checkCmdStart(command) {
77
+ if (!/\bcmd(?:\.exe)?\s+\/c\s+start\b/i.test(command)) return;
78
+ if (/\bcmd(?:\.exe)?\s+\/c\s+start\s+(""|''|`"")?\s*\/(?:min|b)\b/i.test(command)) return;
79
+ block(
80
+ '`cmd /c start` must use `/min` for visible tools or `/b`/a hidden wrapper for background tools.',
81
+ { kind: 'cmd-start' },
82
+ );
83
+ }
84
+
85
+ function checkDirectShellLaunch(command) {
86
+ if (hasHiddenIntent(command)) return;
87
+ if (/\bpowershell(?:\.exe)?\b[^|\n]*(?:-File\s+[^|\n]*\.ps1|\.ps1\b)/i.test(command)) {
88
+ block(
89
+ 'PowerShell script launches from agent tooling must use `-WindowStyle Hidden -NonInteractive` or a hidden wrapper.',
90
+ { kind: 'powershell-ps1' },
91
+ );
92
+ }
93
+ }
94
+
95
+ async function main() {
96
+ let raw;
97
+ try { raw = JSON.parse(await readStdin()); } catch { process.exit(0); }
98
+ const command = toolText(raw);
99
+ if (!command) pass({ reason: 'no-command' });
100
+
101
+ checkPlaywright(command);
102
+ checkPowerShell(command);
103
+ checkCmdStart(command);
104
+ checkDirectShellLaunch(command);
105
+
106
+ pass({ reason: 'clean' });
107
+ }
108
+
109
+ main().catch((e) => block(`Foreground process gate crashed: ${e.message}`));
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+ const path = require('path');
6
+
7
+ const logPath = path.join(os.homedir(), '.claude', 'hook-events.jsonl');
8
+
9
+ module.exports = function hookLog(hook, event, verdict, details = {}) {
10
+ try {
11
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
12
+ fs.appendFileSync(
13
+ logPath,
14
+ JSON.stringify({
15
+ ts: new Date().toISOString(),
16
+ hook,
17
+ event,
18
+ verdict,
19
+ details,
20
+ }) + '\n',
21
+ );
22
+ } catch (_) {
23
+ // Hooks should never fail just because telemetry could not be written.
24
+ }
25
+ };
@@ -0,0 +1,47 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [string]$HookScript
4
+ )
5
+
6
+ $ErrorActionPreference = "Stop"
7
+
8
+ $nodeCmd = Get-Command node.exe -ErrorAction SilentlyContinue
9
+ if (-not $nodeCmd) {
10
+ $nodeCmd = Get-Command node -ErrorAction SilentlyContinue
11
+ }
12
+ $node = if ($nodeCmd) { $nodeCmd.Source } else { $null }
13
+ if (-not $node) {
14
+ $node = if ($nodeCmd) { $nodeCmd.Path } else { $null }
15
+ }
16
+ if (-not $node) {
17
+ [Console]::Error.WriteLine("run-hidden-hook: node was not found on PATH")
18
+ exit 127
19
+ }
20
+
21
+ $stdinText = [Console]::In.ReadToEnd()
22
+
23
+ $psi = [System.Diagnostics.ProcessStartInfo]::new()
24
+ $psi.FileName = $node
25
+ $psi.UseShellExecute = $false
26
+ $psi.CreateNoWindow = $true
27
+ $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
28
+ $psi.RedirectStandardInput = $true
29
+ $psi.RedirectStandardOutput = $true
30
+ $psi.RedirectStandardError = $true
31
+ $psi.Arguments = "`"$HookScript`""
32
+
33
+ $proc = [System.Diagnostics.Process]::new()
34
+ $proc.StartInfo = $psi
35
+ $null = $proc.Start()
36
+
37
+ $proc.StandardInput.Write($stdinText)
38
+ $proc.StandardInput.Close()
39
+
40
+ $stdout = $proc.StandardOutput.ReadToEnd()
41
+ $stderr = $proc.StandardError.ReadToEnd()
42
+ $proc.WaitForExit()
43
+
44
+ if ($stdout) { [Console]::Out.Write($stdout) }
45
+ if ($stderr) { [Console]::Error.Write($stderr) }
46
+
47
+ exit $proc.ExitCode