aiwg
Version:
Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo
64 lines • 2.35 kB
JavaScript
/**
* Copilot hook translator — emits dual-format JSON: a workflow file at
* `.github/hooks/<id>.json` plus an inline `hooks:` block embedded in the
* agent .agent.md frontmatter when the hook targets a specific agent.
*
* Per the parity research, Copilot hook discovery is partially documented;
* the emission here is conservative — produces the shape Copilot Chat is
* known to consume, marks AIWG provenance, and stages behind the feature
* flag handled by the orchestrator.
*/
import { promises as fs } from 'node:fs';
import * as path from 'node:path';
import { substituteEnvVars } from './shim.js';
const COPILOT_EVENT_MAP = {
PreToolUse: 'pre_tool_use',
PostToolUse: 'post_tool_use',
UserPromptSubmit: 'pre_chat',
SessionStart: 'session_start',
SessionEnd: 'session_end',
Stop: 'session_end',
};
export async function translateForCopilot(source, options) {
const result = {
provider: 'copilot',
emittedPaths: [],
warnings: [],
skipped: false,
};
if (source.degradeOn?.includes('copilot')) {
result.skipped = true;
result.skipReason = 'degrade-on declared copilot';
return result;
}
const hooksDir = path.join(options.projectPath, '.github', 'hooks');
const filePath = path.join(hooksDir, `${source.id}.json`);
const events = source.events
.map((e) => COPILOT_EVENT_MAP[e])
.filter((e) => Boolean(e));
if (events.length === 0) {
result.skipped = true;
result.skipReason = 'no Copilot-mapped events';
return result;
}
const subCommand = substituteEnvVars(source.command, 'copilot');
const subArgs = (source.args || []).map((a) => substituteEnvVars(a, 'copilot'));
const payload = {
_aiwg_managed: true,
_aiwg_id: source.id,
description: source.description,
events,
command: subCommand,
args: subArgs,
safety_critical: !!source.safetyCritical,
};
if (options.dryRun) {
result.emittedPaths.push(filePath + ' (dry-run)');
return result;
}
await fs.mkdir(hooksDir, { recursive: true });
await fs.writeFile(filePath, JSON.stringify(payload, null, 2) + '\n', 'utf8');
result.emittedPaths.push(filePath);
return result;
}
//# sourceMappingURL=copilot-translator.js.map