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
88 lines (86 loc) • 3.65 kB
JavaScript
import { checkRepoAccess, findRepoEntry, formatRepoAccessEntry, loadRepoAccessManifest, } from '../../policy/repo-access.js';
function valueAfter(args, flag) {
const index = args.indexOf(flag);
if (index < 0)
return null;
return args[index + 1] ?? null;
}
function printHelp() {
console.log(`
aiwg repo-access — repo authorization manifest preflight
Usage:
aiwg repo-access list
aiwg repo-access explain --path <repo-or-file>
aiwg repo-access check --path <repo-or-file> --action <read|write|commit|push|issue-comment|service-action|destructive>
Manifest:
.aiwg/ops/security/repo-access.manifest.yaml
.aiwg/security/repo-access.manifest.yaml (fallback)
`);
}
async function handleRepoAccess(ctx) {
const [subcommand = 'help', ...args] = ctx.args;
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
printHelp();
return { exitCode: 0 };
}
try {
const manifest = loadRepoAccessManifest(ctx.cwd);
if (subcommand === 'list') {
console.log(`Repo access manifest: ${manifest.path}`);
console.log(`Default policy: ${manifest.defaultPolicy}`);
for (const repo of manifest.repos) {
console.log(`- ${formatRepoAccessEntry(repo)}`);
}
return { exitCode: 0 };
}
if (subcommand === 'explain') {
const requestedPath = valueAfter(args, '--path');
if (!requestedPath)
return { exitCode: 2, message: 'repo-access explain requires --path <repo-or-file>' };
const entry = findRepoEntry(manifest, requestedPath, ctx.cwd);
if (!entry) {
console.log(`Path: ${requestedPath}`);
console.log('Matched repo: none');
console.log('Decision: unlisted repo/path defaults to denied');
return { exitCode: 0 };
}
console.log(`Path: ${requestedPath}`);
console.log(`Matched repo: ${formatRepoAccessEntry(entry)}`);
return { exitCode: 0 };
}
if (subcommand === 'check') {
const requestedPath = valueAfter(args, '--path');
const action = valueAfter(args, '--action');
if (!requestedPath)
return { exitCode: 2, message: 'repo-access check requires --path <repo-or-file>' };
if (!action)
return { exitCode: 2, message: 'repo-access check requires --action <action>' };
const decision = checkRepoAccess(manifest, requestedPath, action, ctx.cwd);
const status = decision.allowed ? 'ALLOW' : 'DENY';
console.log(`${status} ${decision.action} ${decision.requestedPath}`);
console.log(decision.reason);
if (decision.matchedRepo) {
console.log(`matched: ${formatRepoAccessEntry(decision.matchedRepo)}`);
}
return { exitCode: decision.allowed ? 0 : 1 };
}
return { exitCode: 2, message: `Unknown repo-access subcommand: ${subcommand}` };
}
catch (error) {
return {
exitCode: 2,
message: error instanceof Error ? error.message : String(error),
error: error instanceof Error ? error : undefined,
};
}
}
export const repoAccessHandler = {
id: 'repo-access',
name: 'Repo Access',
description: 'Validate and query repo access manifest permissions',
category: 'utility',
aliases: [],
execute: handleRepoAccess,
};
export const repoAccessHandlers = [repoAccessHandler];
//# sourceMappingURL=repo-access.js.map