feat(framework): superpowers enforcement, typecheck hook, file-ownership rules (#451)
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #451.
This commit is contained in:
@@ -78,6 +78,82 @@ function checkSoul(): void {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Claude settings validation ─────────────────────────────────────────────
|
||||
|
||||
interface SettingsAudit {
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
function auditClaudeSettings(): SettingsAudit {
|
||||
const warnings: string[] = [];
|
||||
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
||||
const settings = readJson(settingsPath);
|
||||
|
||||
if (!settings) {
|
||||
warnings.push('~/.claude/settings.json not found — hooks and plugins will be missing');
|
||||
return { warnings };
|
||||
}
|
||||
|
||||
// Check required hooks
|
||||
const hooks = settings['hooks'] as Record<string, unknown[]> | undefined;
|
||||
|
||||
const requiredPreToolUse = ['prevent-memory-write.sh'];
|
||||
const requiredPostToolUse = ['qa-hook-stdin.sh', 'typecheck-hook.sh'];
|
||||
|
||||
const preHooks = (hooks?.['PreToolUse'] ?? []) as Array<Record<string, unknown>>;
|
||||
const postHooks = (hooks?.['PostToolUse'] ?? []) as Array<Record<string, unknown>>;
|
||||
|
||||
const preCommands = preHooks.flatMap((h) => {
|
||||
const inner = (h['hooks'] ?? []) as Array<Record<string, unknown>>;
|
||||
return inner.map((ih) => String(ih['command'] ?? ''));
|
||||
});
|
||||
const postCommands = postHooks.flatMap((h) => {
|
||||
const inner = (h['hooks'] ?? []) as Array<Record<string, unknown>>;
|
||||
return inner.map((ih) => String(ih['command'] ?? ''));
|
||||
});
|
||||
|
||||
for (const script of requiredPreToolUse) {
|
||||
if (!preCommands.some((c) => c.includes(script))) {
|
||||
warnings.push(`Missing PreToolUse hook: ${script}`);
|
||||
}
|
||||
}
|
||||
for (const script of requiredPostToolUse) {
|
||||
if (!postCommands.some((c) => c.includes(script))) {
|
||||
warnings.push(`Missing PostToolUse hook: ${script}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check required plugins
|
||||
const plugins = (settings['enabledPlugins'] ?? {}) as Record<string, boolean>;
|
||||
const requiredPlugins = ['feature-dev', 'pr-review-toolkit', 'code-review'];
|
||||
|
||||
for (const plugin of requiredPlugins) {
|
||||
const found = Object.keys(plugins).some((k) => k.startsWith(plugin) && plugins[k]);
|
||||
if (!found) {
|
||||
warnings.push(`Missing plugin: ${plugin}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check enableAllMcpTools
|
||||
if (!settings['enableAllMcpTools']) {
|
||||
warnings.push('enableAllMcpTools is not true — MCP tools may require per-tool approval');
|
||||
}
|
||||
|
||||
return { warnings };
|
||||
}
|
||||
|
||||
function printSettingsWarnings(audit: SettingsAudit): void {
|
||||
if (audit.warnings.length === 0) return;
|
||||
|
||||
console.log('\n[mosaic] Claude Code settings audit:');
|
||||
for (const w of audit.warnings) {
|
||||
console.log(` ⚠ ${w}`);
|
||||
}
|
||||
console.log(
|
||||
'[mosaic] Run: mosaic doctor — or see ~/.config/mosaic/runtime/claude/RUNTIME.md for required settings.\n',
|
||||
);
|
||||
}
|
||||
|
||||
function checkSequentialThinking(runtime: string): void {
|
||||
const checker = fwScript('mosaic-ensure-sequential-thinking');
|
||||
if (!existsSync(checker)) return; // Skip if checker doesn't exist
|
||||
@@ -407,6 +483,10 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev
|
||||
|
||||
switch (runtime) {
|
||||
case 'claude': {
|
||||
// Audit Claude Code settings and warn about missing hooks/plugins
|
||||
const settingsAudit = auditClaudeSettings();
|
||||
printSettingsWarnings(settingsAudit);
|
||||
|
||||
const prompt = buildRuntimePrompt('claude');
|
||||
const cliArgs = yolo ? ['--dangerously-skip-permissions'] : [];
|
||||
cliArgs.push('--append-system-prompt', prompt);
|
||||
|
||||
Reference in New Issue
Block a user