Full port of llm-security plugin for internal use on Windows with GitHub Copilot CLI. Protocol translation layer (copilot-hook-runner.mjs) normalizes Copilot camelCase I/O to Claude Code snake_case format — all original hook scripts run unmodified. - 8 hooks with protocol translation (stdin/stdout/exit code) - 18 SKILL.md skills (Agent Skills Open Standard) - 6 .agent.md agent definitions - 20 scanners + 14 scanner lib modules (unchanged) - 14 knowledge files (unchanged) - 39 test files including copilot-port-verify.mjs (17 tests) - Windows-ready: node:path, os.tmpdir(), process.execPath, no bash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
73 lines
1.8 KiB
JavaScript
73 lines
1.8 KiB
JavaScript
#!/usr/bin/env node
|
|
// copilot-adapter.mjs — Normalizes GitHub Copilot hook I/O to internal format.
|
|
//
|
|
// Copilot CLI hooks receive JSON on stdin with camelCase field names
|
|
// (toolName, toolArgs, toolResult) and signal blocking via exit code 2
|
|
// or stdout JSON with permissionDecision: "deny".
|
|
//
|
|
// This adapter provides a consistent interface so hook logic stays
|
|
// platform-agnostic. If Copilot changes field names, only this file
|
|
// needs updating.
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
/**
|
|
* Parse hook input from stdin. Returns normalized object or null on failure.
|
|
* Supports both Copilot (camelCase) and Claude Code (snake_case) field names.
|
|
*/
|
|
export function parseInput() {
|
|
try {
|
|
const raw = readFileSync(0, 'utf-8');
|
|
const input = JSON.parse(raw);
|
|
return {
|
|
toolName: input.toolName ?? input.tool_name ?? '',
|
|
toolInput: input.toolArgs ?? input.tool_input ?? {},
|
|
toolOutput: input.toolResult ?? input.tool_output ?? '',
|
|
message: input.message ?? {},
|
|
sessionId: input.sessionId ?? input.session_id ?? '',
|
|
raw: input,
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Block the tool call with a reason message.
|
|
*/
|
|
export function block(reason) {
|
|
process.stderr.write(reason + '\n');
|
|
process.stdout.write(JSON.stringify({
|
|
permissionDecision: 'deny',
|
|
reason,
|
|
}));
|
|
process.exit(2);
|
|
}
|
|
|
|
/**
|
|
* Allow the tool call, optionally with an advisory message.
|
|
*/
|
|
export function allow(message) {
|
|
if (message) {
|
|
process.stdout.write(JSON.stringify({
|
|
permissionDecision: 'allow',
|
|
message,
|
|
}));
|
|
}
|
|
process.exit(0);
|
|
}
|
|
|
|
/**
|
|
* Emit a warning to stderr without blocking. Exit 0.
|
|
*/
|
|
export function warn(message) {
|
|
process.stderr.write(message + '\n');
|
|
process.exit(0);
|
|
}
|
|
|
|
/**
|
|
* Fail-open: exit 0 silently. Used when input can't be parsed.
|
|
*/
|
|
export function failOpen() {
|
|
process.exit(0);
|
|
}
|