@posthog/wizard 2.0.1 → 2.1.0
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.
- package/dist/bin.js +53 -8
- package/dist/bin.js.map +1 -1
- package/dist/src/__tests__/cli.test.js +50 -3
- package/dist/src/__tests__/cli.test.js.map +1 -1
- package/dist/src/__tests__/package-json.test.d.ts +1 -0
- package/dist/src/__tests__/package-json.test.js +173 -0
- package/dist/src/__tests__/package-json.test.js.map +1 -0
- package/dist/src/frameworks/angular/angular-wizard-agent.js +1 -6
- package/dist/src/frameworks/angular/angular-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/astro/astro-wizard-agent.js +1 -4
- package/dist/src/frameworks/astro/astro-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js +1 -4
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/nuxt/nuxt-wizard-agent.js +1 -4
- package/dist/src/frameworks/nuxt/nuxt-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/react-native/react-native-wizard-agent.js +1 -6
- package/dist/src/frameworks/react-native/react-native-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/react-router/react-router-wizard-agent.js +1 -6
- package/dist/src/frameworks/react-router/react-router-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/tanstack-router/tanstack-router-wizard-agent.js +1 -6
- package/dist/src/frameworks/tanstack-router/tanstack-router-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/tanstack-start/tanstack-start-wizard-agent.js +1 -6
- package/dist/src/frameworks/tanstack-start/tanstack-start-wizard-agent.js.map +1 -1
- package/dist/src/frameworks/vue/vue-wizard-agent.js +1 -4
- package/dist/src/frameworks/vue/vue-wizard-agent.js.map +1 -1
- package/dist/src/lib/__tests__/agent-interface.test.js +1 -0
- package/dist/src/lib/__tests__/agent-interface.test.js.map +1 -1
- package/dist/src/lib/__tests__/yara-hooks.test.d.ts +1 -0
- package/dist/src/lib/__tests__/yara-hooks.test.js +432 -0
- package/dist/src/lib/__tests__/yara-hooks.test.js.map +1 -0
- package/dist/src/lib/__tests__/yara-scanner.test.d.ts +1 -0
- package/dist/src/lib/__tests__/yara-scanner.test.js +613 -0
- package/dist/src/lib/__tests__/yara-scanner.test.js.map +1 -0
- package/dist/src/lib/agent-interface.d.ts +4 -2
- package/dist/src/lib/agent-interface.js +40 -26
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/agent-runner.js +49 -15
- package/dist/src/lib/agent-runner.js.map +1 -1
- package/dist/src/lib/commandments.js +1 -0
- package/dist/src/lib/commandments.js.map +1 -1
- package/dist/src/lib/constants.d.ts +4 -3
- package/dist/src/lib/constants.js +3 -2
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/middleware/benchmark.js +2 -6
- package/dist/src/lib/middleware/benchmark.js.map +1 -1
- package/dist/src/lib/middleware/benchmarks/json-writer.js +1 -2
- package/dist/src/lib/middleware/benchmarks/json-writer.js.map +1 -1
- package/dist/src/lib/middleware/benchmarks/summary.js +6 -10
- package/dist/src/lib/middleware/benchmarks/summary.js.map +1 -1
- package/dist/src/lib/skill-install.d.ts +10 -0
- package/dist/src/lib/skill-install.js +23 -0
- package/dist/src/lib/skill-install.js.map +1 -0
- package/dist/src/lib/version.d.ts +1 -1
- package/dist/src/lib/version.js +1 -1
- package/dist/src/lib/version.js.map +1 -1
- package/dist/src/lib/wizard-session.d.ts +13 -0
- package/dist/src/lib/wizard-session.js +3 -0
- package/dist/src/lib/wizard-session.js.map +1 -1
- package/dist/src/lib/yara-hooks.d.ts +44 -0
- package/dist/src/lib/yara-hooks.js +377 -0
- package/dist/src/lib/yara-hooks.js.map +1 -0
- package/dist/src/lib/yara-scanner.d.ts +61 -0
- package/dist/src/lib/yara-scanner.js +328 -0
- package/dist/src/lib/yara-scanner.js.map +1 -0
- package/dist/src/run.d.ts +3 -0
- package/dist/src/run.js +11 -2
- package/dist/src/run.js.map +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +2 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.js +1 -1
- package/dist/src/steps/add-mcp-server-to-clients/index.js.map +1 -1
- package/dist/src/steps/add-or-update-environment-variables.js +9 -10
- package/dist/src/steps/add-or-update-environment-variables.js.map +1 -1
- package/dist/src/steps/upload-environment-variables/providers/vercel.js +4 -8
- package/dist/src/steps/upload-environment-variables/providers/vercel.js.map +1 -1
- package/dist/src/ui/logging-ui.d.ts +5 -0
- package/dist/src/ui/logging-ui.js +3 -0
- package/dist/src/ui/logging-ui.js.map +1 -1
- package/dist/src/ui/tui/ink-ui.d.ts +5 -0
- package/dist/src/ui/tui/ink-ui.js +3 -0
- package/dist/src/ui/tui/ink-ui.js.map +1 -1
- package/dist/src/ui/tui/primitives/Divider.d.ts +6 -0
- package/dist/src/ui/tui/primitives/Divider.js +15 -0
- package/dist/src/ui/tui/primitives/Divider.js.map +1 -0
- package/dist/src/ui/tui/primitives/index.d.ts +1 -0
- package/dist/src/ui/tui/primitives/index.js +1 -0
- package/dist/src/ui/tui/primitives/index.js.map +1 -1
- package/dist/src/ui/tui/router.d.ts +2 -1
- package/dist/src/ui/tui/router.js +1 -0
- package/dist/src/ui/tui/router.js.map +1 -1
- package/dist/src/ui/tui/screen-registry.js +2 -0
- package/dist/src/ui/tui/screen-registry.js.map +1 -1
- package/dist/src/ui/tui/screens/IntroScreen.js +18 -2
- package/dist/src/ui/tui/screens/IntroScreen.js.map +1 -1
- package/dist/src/ui/tui/screens/PortConflictScreen.d.ts +11 -0
- package/dist/src/ui/tui/screens/PortConflictScreen.js +30 -0
- package/dist/src/ui/tui/screens/PortConflictScreen.js.map +1 -0
- package/dist/src/ui/tui/store.d.ts +18 -0
- package/dist/src/ui/tui/store.js +25 -0
- package/dist/src/ui/tui/store.js.map +1 -1
- package/dist/src/ui/wizard-ui.d.ts +6 -0
- package/dist/src/ui/wizard-ui.js.map +1 -1
- package/dist/src/utils/debug.js +1 -5
- package/dist/src/utils/debug.js.map +1 -1
- package/dist/src/utils/logging.js +7 -10
- package/dist/src/utils/logging.js.map +1 -1
- package/dist/src/utils/oauth.js +44 -4
- package/dist/src/utils/oauth.js.map +1 -1
- package/dist/src/utils/package-json.d.ts +5 -0
- package/dist/src/utils/package-json.js +20 -0
- package/dist/src/utils/package-json.js.map +1 -1
- package/dist/src/utils/rules/universal.md +12 -0
- package/dist/src/utils/setup-utils.js +12 -14
- package/dist/src/utils/setup-utils.js.map +1 -1
- package/dist/src/utils/types.d.ts +9 -0
- package/dist/src/utils/types.js.map +1 -1
- package/package.json +1 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../../../src/lib/middleware/benchmarks/summary.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { getUI, type SpinnerHandle } from '../../../ui';\nimport { AgentSignals } from '../../agent-interface';\nimport type { Middleware, MiddlewareContext, MiddlewareStore } from '../types';\nimport type { TokenData } from './token-tracker';\nimport type { TurnData } from './turn-counter';\nimport type { CostData } from './cost-tracker';\nimport type { DurationData } from './duration-tracker';\nimport type { CompactionData } from './compaction-tracker';\nimport type { ContextSizeData } from './context-size-tracker';\nimport type { CacheData } from './cache-tracker';\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n const m = Math.floor(s / 60);\n return m > 0 ? `${m}m ${s % 60}s` : `${s}s`;\n}\n\nfunction fmtTok(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1000).toFixed(1)}K`;\n return n.toLocaleString();\n}\n\nfunction fmtCost(usd: number): string {\n if (usd > 0 && usd < 0.01) return `$${usd.toFixed(4)}`;\n return `$${usd.toFixed(2)}`;\n}\n\ninterface PhaseStats {\n phase: string;\n durationMs: number;\n turns: number;\n inputTokens: number;\n outputTokens: number;\n cacheRead: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n cost: number;\n compactions: number;\n contextOut: number | undefined;\n}\n\nfunction printPhase(s: PhaseStats): string {\n const baseIn = Math.max(\n 0,\n s.inputTokens - s.cacheRead - s.cacheCreation5m - s.cacheCreation1h,\n );\n return [\n `${chalk.bold(s.phase)}: ${fmtDuration(s.durationMs)}, ${\n s.turns\n } turns, cost: ${fmtCost(s.cost)}`,\n ` in: ${fmtTok(baseIn)}, out: ${fmtTok(\n s.outputTokens,\n )}, cache_read: ${fmtTok(s.cacheRead)}, cache_5m: ${fmtTok(\n s.cacheCreation5m,\n )}, cache_1h: ${fmtTok(s.cacheCreation1h)}`,\n s.compactions > 0 ? ` ${s.compactions} compaction(s)` : null,\n s.contextOut !== undefined ? ` ctx_out: ${fmtTok(s.contextOut)}` : null,\n ]\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getPhaseStats(i: number, ctx: MiddlewareContext): PhaseStats | null {\n const duration = ctx.get<DurationData>('duration');\n const dur = duration?.phaseSnapshots[i];\n if (!dur) return null;\n\n const tokens = ctx.get<TokenData>('tokens');\n const turns = ctx.get<TurnData>('turns');\n const cost = ctx.get<CostData>('cost');\n const compactions = ctx.get<CompactionData>('compactions');\n const contextSize = ctx.get<ContextSizeData>('contextSize');\n const cache = ctx.get<CacheData>('cache');\n\n return {\n phase: dur.phase,\n durationMs: dur.durationMs,\n turns: turns?.phaseSnapshots[i]?.turns ?? 0,\n inputTokens: tokens?.phaseSnapshots[i]?.inputTokens ?? 0,\n outputTokens: tokens?.phaseSnapshots[i]?.outputTokens ?? 0,\n cacheRead: cache?.phaseSnapshots[i]?.cacheReadTokens ?? 0,\n cacheCreation5m: cache?.phaseSnapshots[i]?.cacheCreation5m ?? 0,\n cacheCreation1h: cache?.phaseSnapshots[i]?.cacheCreation1h ?? 0,\n cost: cost?.phaseCosts[i]?.cost ?? 0,\n compactions: compactions?.phaseSnapshots[i]?.compactions ?? 0,\n contextOut: contextSize?.phaseSnapshots[i]?.contextTokensOut,\n };\n}\n\nexport class SummaryPlugin implements Middleware {\n readonly name = 'summary';\n\n private spinner: SpinnerHandle;\n\n constructor(spinner: SpinnerHandle) {\n this.spinner = spinner;\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const idx = (duration?.phaseSnapshots.length ?? 1) - 1;\n const stats = getPhaseStats(idx, ctx);\n\n if (stats) {\n this.spinner.stop(\n `${chalk.cyan(AgentSignals.BENCHMARK)} ${printPhase(stats)}`,\n );\n } else {\n this.spinner.stop(`${chalk.cyan(AgentSignals.BENCHMARK)} ${fromPhase}`);\n }\n\n getUI().log.info(\n `${chalk.cyan(AgentSignals.BENCHMARK)} Starting phase: ${chalk.bold(\n toPhase,\n )}`,\n );\n this.spinner.start(`Integrating PostHog (${toPhase})...`);\n }\n\n onFinalize(\n _resultMessage: any,\n totalDurationMs: number,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const cost = ctx.get<CostData>('cost');\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n\n const phaseCount = duration?.phaseSnapshots.length ?? 0;\n const totalCost = cost?.totalCost ?? 0;\n\n getUI().log.info('');\n getUI().log.info(\n `${chalk.green('◇')} ${chalk.cyan(\n AgentSignals.BENCHMARK,\n )} ${phaseCount} phases in ${fmtDuration(\n totalDurationMs,\n )}, cost: ${fmtCost(totalCost)}`,\n );\n getUI().log.info(\n ` total in: ${fmtTok(tokens?.totalInput ?? 0)}, out: ${fmtTok(\n tokens?.totalOutput ?? 0,\n )}, cache_read: ${fmtTok(cache?.totalRead ?? 0)}, cache_5m: ${fmtTok(\n cache?.totalCreation5m ?? 0,\n )}, cache_1h: ${fmtTok(cache?.totalCreation1h ?? 0)}`,\n );\n getUI().log.info('');\n getUI().log.info(\n `${chalk.blue('●')} ${chalk.cyan(\n AgentSignals.BENCHMARK,\n )} Summary by phase:`,\n );\n\n if (duration?.phaseSnapshots) {\n for (let i = 0; i < duration.phaseSnapshots.length; i++) {\n const stats = getPhaseStats(i, ctx);\n if (stats) {\n getUI().log.info(printPhase(stats));\n }\n }\n }\n\n getUI().log.info('');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../../../src/lib/middleware/benchmarks/summary.ts"],"names":[],"mappings":"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","sourcesContent":["import { getUI, type SpinnerHandle } from '../../../ui';\nimport { AgentSignals } from '../../agent-interface';\nimport type { Middleware, MiddlewareContext, MiddlewareStore } from '../types';\nimport type { TokenData } from './token-tracker';\nimport type { TurnData } from './turn-counter';\nimport type { CostData } from './cost-tracker';\nimport type { DurationData } from './duration-tracker';\nimport type { CompactionData } from './compaction-tracker';\nimport type { ContextSizeData } from './context-size-tracker';\nimport type { CacheData } from './cache-tracker';\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n const m = Math.floor(s / 60);\n return m > 0 ? `${m}m ${s % 60}s` : `${s}s`;\n}\n\nfunction fmtTok(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1000).toFixed(1)}K`;\n return n.toLocaleString();\n}\n\nfunction fmtCost(usd: number): string {\n if (usd > 0 && usd < 0.01) return `$${usd.toFixed(4)}`;\n return `$${usd.toFixed(2)}`;\n}\n\ninterface PhaseStats {\n phase: string;\n durationMs: number;\n turns: number;\n inputTokens: number;\n outputTokens: number;\n cacheRead: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n cost: number;\n compactions: number;\n contextOut: number | undefined;\n}\n\nfunction printPhase(s: PhaseStats): string {\n const baseIn = Math.max(\n 0,\n s.inputTokens - s.cacheRead - s.cacheCreation5m - s.cacheCreation1h,\n );\n return [\n `${s.phase}: ${fmtDuration(s.durationMs)}, ${\n s.turns\n } turns, cost: ${fmtCost(s.cost)}`,\n ` in: ${fmtTok(baseIn)}, out: ${fmtTok(\n s.outputTokens,\n )}, cache_read: ${fmtTok(s.cacheRead)}, cache_5m: ${fmtTok(\n s.cacheCreation5m,\n )}, cache_1h: ${fmtTok(s.cacheCreation1h)}`,\n s.compactions > 0 ? ` ${s.compactions} compaction(s)` : null,\n s.contextOut !== undefined ? ` ctx_out: ${fmtTok(s.contextOut)}` : null,\n ]\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getPhaseStats(i: number, ctx: MiddlewareContext): PhaseStats | null {\n const duration = ctx.get<DurationData>('duration');\n const dur = duration?.phaseSnapshots[i];\n if (!dur) return null;\n\n const tokens = ctx.get<TokenData>('tokens');\n const turns = ctx.get<TurnData>('turns');\n const cost = ctx.get<CostData>('cost');\n const compactions = ctx.get<CompactionData>('compactions');\n const contextSize = ctx.get<ContextSizeData>('contextSize');\n const cache = ctx.get<CacheData>('cache');\n\n return {\n phase: dur.phase,\n durationMs: dur.durationMs,\n turns: turns?.phaseSnapshots[i]?.turns ?? 0,\n inputTokens: tokens?.phaseSnapshots[i]?.inputTokens ?? 0,\n outputTokens: tokens?.phaseSnapshots[i]?.outputTokens ?? 0,\n cacheRead: cache?.phaseSnapshots[i]?.cacheReadTokens ?? 0,\n cacheCreation5m: cache?.phaseSnapshots[i]?.cacheCreation5m ?? 0,\n cacheCreation1h: cache?.phaseSnapshots[i]?.cacheCreation1h ?? 0,\n cost: cost?.phaseCosts[i]?.cost ?? 0,\n compactions: compactions?.phaseSnapshots[i]?.compactions ?? 0,\n contextOut: contextSize?.phaseSnapshots[i]?.contextTokensOut,\n };\n}\n\nexport class SummaryPlugin implements Middleware {\n readonly name = 'summary';\n\n private spinner: SpinnerHandle;\n\n constructor(spinner: SpinnerHandle) {\n this.spinner = spinner;\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const idx = (duration?.phaseSnapshots.length ?? 1) - 1;\n const stats = getPhaseStats(idx, ctx);\n\n if (stats) {\n this.spinner.stop(`${AgentSignals.BENCHMARK} ${printPhase(stats)}`);\n } else {\n this.spinner.stop(`${AgentSignals.BENCHMARK} ${fromPhase}`);\n }\n\n getUI().log.info(`${AgentSignals.BENCHMARK} Starting phase: ${toPhase}`);\n this.spinner.start(`Integrating PostHog (${toPhase})...`);\n }\n\n onFinalize(\n _resultMessage: any,\n totalDurationMs: number,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const cost = ctx.get<CostData>('cost');\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n\n const phaseCount = duration?.phaseSnapshots.length ?? 0;\n const totalCost = cost?.totalCost ?? 0;\n\n getUI().log.info('');\n getUI().log.info(\n `◇ ${AgentSignals.BENCHMARK} ${phaseCount} phases in ${fmtDuration(\n totalDurationMs,\n )}, cost: ${fmtCost(totalCost)}`,\n );\n getUI().log.info(\n ` total in: ${fmtTok(tokens?.totalInput ?? 0)}, out: ${fmtTok(\n tokens?.totalOutput ?? 0,\n )}, cache_read: ${fmtTok(cache?.totalRead ?? 0)}, cache_5m: ${fmtTok(\n cache?.totalCreation5m ?? 0,\n )}, cache_1h: ${fmtTok(cache?.totalCreation1h ?? 0)}`,\n );\n getUI().log.info('');\n getUI().log.info(`● ${AgentSignals.BENCHMARK} Summary by phase:`);\n\n if (duration?.phaseSnapshots) {\n for (let i = 0; i < duration.phaseSnapshots.length; i++) {\n const stats = getPhaseStats(i, ctx);\n if (stats) {\n getUI().log.info(printPhase(stats));\n }\n }\n }\n\n getUI().log.info('');\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if command is a PostHog skill installation from MCP.
|
|
3
|
+
* We control the MCP server, so we only need to verify:
|
|
4
|
+
* 1. It installs to .claude/skills/
|
|
5
|
+
* 2. It downloads from our GitHub releases or localhost (dev)
|
|
6
|
+
*
|
|
7
|
+
* Extracted to its own module to avoid a circular dependency
|
|
8
|
+
* between agent-interface.ts and yara-hooks.ts.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isSkillInstallCommand(command: string): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isSkillInstallCommand = isSkillInstallCommand;
|
|
4
|
+
/**
|
|
5
|
+
* Check if command is a PostHog skill installation from MCP.
|
|
6
|
+
* We control the MCP server, so we only need to verify:
|
|
7
|
+
* 1. It installs to .claude/skills/
|
|
8
|
+
* 2. It downloads from our GitHub releases or localhost (dev)
|
|
9
|
+
*
|
|
10
|
+
* Extracted to its own module to avoid a circular dependency
|
|
11
|
+
* between agent-interface.ts and yara-hooks.ts.
|
|
12
|
+
*/
|
|
13
|
+
function isSkillInstallCommand(command) {
|
|
14
|
+
if (!command.startsWith('mkdir -p .claude/skills/'))
|
|
15
|
+
return false;
|
|
16
|
+
const urlMatch = command.match(/curl -sL ['"]([^'"]+)['"]/);
|
|
17
|
+
if (!urlMatch)
|
|
18
|
+
return false;
|
|
19
|
+
const url = urlMatch[1];
|
|
20
|
+
return (url.startsWith('https://github.com/PostHog/context-mill/releases/') ||
|
|
21
|
+
/^http:\/\/localhost:\d+\//.test(url));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=skill-install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-install.js","sourceRoot":"","sources":["../../../src/lib/skill-install.ts"],"names":[],"mappings":";;AASA,sDAWC;AApBD;;;;;;;;GAQG;AACH,SAAgB,qBAAqB,CAAC,OAAe;IACnD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC;QAAE,OAAO,KAAK,CAAC;IAElE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC5D,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5B,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,CACL,GAAG,CAAC,UAAU,CAAC,mDAAmD,CAAC;QACnE,2BAA2B,CAAC,IAAI,CAAC,GAAG,CAAC,CACtC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Check if command is a PostHog skill installation from MCP.\n * We control the MCP server, so we only need to verify:\n * 1. It installs to .claude/skills/\n * 2. It downloads from our GitHub releases or localhost (dev)\n *\n * Extracted to its own module to avoid a circular dependency\n * between agent-interface.ts and yara-hooks.ts.\n */\nexport function isSkillInstallCommand(command: string): boolean {\n if (!command.startsWith('mkdir -p .claude/skills/')) return false;\n\n const urlMatch = command.match(/curl -sL ['\"]([^'\"]+)['\"]/);\n if (!urlMatch) return false;\n\n const url = urlMatch[1];\n return (\n url.startsWith('https://github.com/PostHog/context-mill/releases/') ||\n /^http:\\/\\/localhost:\\d+\\//.test(url)\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "2.0
|
|
1
|
+
export declare const VERSION = "2.1.0";
|
package/dist/src/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":";;;AAAA,8DAA8D;AACjD,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.0
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":";;;AAAA,8DAA8D;AACjD,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.1.0';\n"]}
|
|
@@ -66,6 +66,7 @@ export interface WizardSession {
|
|
|
66
66
|
apiKey?: string;
|
|
67
67
|
menu: boolean;
|
|
68
68
|
benchmark: boolean;
|
|
69
|
+
yaraReport: boolean;
|
|
69
70
|
projectId?: number;
|
|
70
71
|
setupConfirmed: boolean;
|
|
71
72
|
integration: Integration | null;
|
|
@@ -75,6 +76,12 @@ export interface WizardSession {
|
|
|
75
76
|
detectedFrameworkLabel: string | null;
|
|
76
77
|
/** True once framework detection has run (whether it found something or not) */
|
|
77
78
|
detectionComplete: boolean;
|
|
79
|
+
/** Set when the detected framework version is too old for the wizard */
|
|
80
|
+
unsupportedVersion: {
|
|
81
|
+
current: string;
|
|
82
|
+
minimum: string;
|
|
83
|
+
docsUrl: string;
|
|
84
|
+
} | null;
|
|
78
85
|
credentials: {
|
|
79
86
|
accessToken: string;
|
|
80
87
|
projectApiKey: string;
|
|
@@ -93,6 +100,11 @@ export interface WizardSession {
|
|
|
93
100
|
statusPageUrl: string;
|
|
94
101
|
} | null;
|
|
95
102
|
settingsOverrideKeys: string[] | null;
|
|
103
|
+
portConflictProcess: {
|
|
104
|
+
command: string;
|
|
105
|
+
pid: string;
|
|
106
|
+
user: string;
|
|
107
|
+
} | null;
|
|
96
108
|
outroData: OutroData | null;
|
|
97
109
|
additionalFeatureQueue: AdditionalFeature[];
|
|
98
110
|
frameworkConfig: FrameworkConfig | null;
|
|
@@ -111,5 +123,6 @@ export declare function buildSession(args: {
|
|
|
111
123
|
menu?: boolean;
|
|
112
124
|
integration?: Integration;
|
|
113
125
|
benchmark?: boolean;
|
|
126
|
+
yaraReport?: boolean;
|
|
114
127
|
projectId?: string;
|
|
115
128
|
}): WizardSession;
|
|
@@ -79,6 +79,7 @@ function buildSession(args) {
|
|
|
79
79
|
apiKey: args.apiKey,
|
|
80
80
|
menu: args.menu ?? false,
|
|
81
81
|
benchmark: args.benchmark ?? false,
|
|
82
|
+
yaraReport: args.yaraReport ?? false,
|
|
82
83
|
projectId: parseProjectIdArg(args.projectId),
|
|
83
84
|
setupConfirmed: false,
|
|
84
85
|
integration: args.integration ?? null,
|
|
@@ -86,6 +87,7 @@ function buildSession(args) {
|
|
|
86
87
|
typescript: false,
|
|
87
88
|
detectedFrameworkLabel: null,
|
|
88
89
|
detectionComplete: false,
|
|
90
|
+
unsupportedVersion: null,
|
|
89
91
|
runPhase: RunPhase.Idle,
|
|
90
92
|
discoveredFeatures: [],
|
|
91
93
|
llmOptIn: false,
|
|
@@ -96,6 +98,7 @@ function buildSession(args) {
|
|
|
96
98
|
credentials: null,
|
|
97
99
|
serviceStatus: null,
|
|
98
100
|
settingsOverrideKeys: null,
|
|
101
|
+
portConflictProcess: null,
|
|
99
102
|
outroData: null,
|
|
100
103
|
additionalFeatureQueue: [],
|
|
101
104
|
frameworkConfig: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard-session.js","sourceRoot":"","sources":["../../../src/lib/wizard-session.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;
|
|
1
|
+
{"version":3,"file":"wizard-session.js","sourceRoot":"","sources":["../../../src/lib/wizard-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WizardSession — single source of truth for every decision the wizard needs.\n *\n * Populated in layers:\n * CLI args / env vars → populate fields directly\n * Auto-detection → framework, typescript, package manager\n * TUI screens → region, framework disambiguation, etc.\n * OAuth → credentials\n *\n * Business logic reads from the session. Never calls a prompt.\n */\n\nimport type { Integration } from './constants';\nimport type { FrameworkConfig } from './framework-config';\n\nfunction parseProjectIdArg(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const n = Number(value);\n return Number.isInteger(n) && n > 0 ? n : undefined;\n}\n\nexport type CloudRegion = 'us' | 'eu';\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Features discovered by the feature-discovery subagent */\nexport enum DiscoveredFeature {\n Stripe = 'stripe',\n LLM = 'llm',\n}\n\n/** Additional features the agent can integrate after the main setup */\nexport enum AdditionalFeature {\n LLM = 'llm',\n}\n\n/** Human-readable labels for additional features (used in TUI progress) */\nexport const ADDITIONAL_FEATURE_LABELS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: 'LLM analytics',\n};\n\n/** Agent prompts for each additional feature, injected via the stop hook */\nexport const ADDITIONAL_FEATURE_PROMPTS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: `Now integrate LLM analytics with PostHog. Use the PostHog MCP server to find the appropriate LLM analytics skill, install it, and follow its workflow. PostHog basics are already installed. Update the setup report markdown file when complete with additions from this task. `,\n};\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/** Outcome kind for the outro screen */\nexport enum OutroKind {\n Success = 'success',\n Error = 'error',\n Cancel = 'cancel',\n}\n\nexport interface OutroData {\n kind: OutroKind;\n message?: string;\n changes?: string[];\n docsUrl?: string;\n continueUrl?: string;\n}\n\nexport interface WizardSession {\n // From CLI args\n debug: boolean;\n forceInstall: boolean;\n installDir: string;\n ci: boolean;\n signup: boolean;\n localMcp: boolean;\n apiKey?: string;\n menu: boolean;\n benchmark: boolean;\n yaraReport: boolean;\n projectId?: number;\n\n // From detection + screens\n setupConfirmed: boolean;\n integration: Integration | null;\n frameworkContext: Record<string, unknown>;\n typescript: boolean;\n\n /** Human-readable label for the detected framework variant (e.g., \"Django with Wagtail CMS\") */\n detectedFrameworkLabel: string | null;\n\n /** True once framework detection has run (whether it found something or not) */\n detectionComplete: boolean;\n\n /** Set when the detected framework version is too old for the wizard */\n unsupportedVersion: {\n current: string;\n minimum: string;\n docsUrl: string;\n } | null;\n\n // From OAuth\n credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n } | null;\n\n // Lifecycle\n runPhase: RunPhase;\n loginUrl: string | null;\n\n // Feature discovery\n discoveredFeatures: DiscoveredFeature[];\n llmOptIn: boolean;\n\n // Screen completion\n mcpComplete: boolean;\n mcpOutcome: McpOutcome | null;\n mcpInstalledClients: string[];\n\n // Runtime\n serviceStatus: { description: string; statusPageUrl: string } | null;\n settingsOverrideKeys: string[] | null;\n portConflictProcess: { command: string; pid: string; user: string } | null;\n outroData: OutroData | null;\n\n // Additional features queue (drained via stop hook after main integration)\n additionalFeatureQueue: AdditionalFeature[];\n\n // Resolved framework config (set after integration is known)\n frameworkConfig: FrameworkConfig | null;\n}\n\n/**\n * Build a WizardSession from CLI args, pre-populating whatever is known.\n */\nexport function buildSession(args: {\n debug?: boolean;\n forceInstall?: boolean;\n installDir?: string;\n ci?: boolean;\n signup?: boolean;\n localMcp?: boolean;\n apiKey?: string;\n menu?: boolean;\n integration?: Integration;\n benchmark?: boolean;\n yaraReport?: boolean;\n projectId?: string;\n}): WizardSession {\n return {\n debug: args.debug ?? false,\n forceInstall: args.forceInstall ?? false,\n installDir: args.installDir ?? process.cwd(),\n ci: args.ci ?? false,\n signup: args.signup ?? false,\n localMcp: args.localMcp ?? false,\n apiKey: args.apiKey,\n menu: args.menu ?? false,\n benchmark: args.benchmark ?? false,\n yaraReport: args.yaraReport ?? false,\n projectId: parseProjectIdArg(args.projectId),\n\n setupConfirmed: false,\n integration: args.integration ?? null,\n frameworkContext: {},\n typescript: false,\n detectedFrameworkLabel: null,\n detectionComplete: false,\n unsupportedVersion: null,\n\n runPhase: RunPhase.Idle,\n discoveredFeatures: [],\n llmOptIn: false,\n mcpComplete: false,\n mcpOutcome: null,\n mcpInstalledClients: [],\n loginUrl: null,\n credentials: null,\n serviceStatus: null,\n settingsOverrideKeys: null,\n portConflictProcess: null,\n outroData: null,\n additionalFeatureQueue: [],\n frameworkConfig: null,\n };\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YARA hook wiring for the Claude Agent SDK.
|
|
3
|
+
*
|
|
4
|
+
* Creates PreToolUse and PostToolUse hook callback arrays that
|
|
5
|
+
* integrate the YARA scanner into the wizard's agent loop. These
|
|
6
|
+
* hooks are registered in the SDK's query() options alongside the
|
|
7
|
+
* existing Stop hook.
|
|
8
|
+
*
|
|
9
|
+
* PreToolUse hooks block dangerous commands before execution.
|
|
10
|
+
* PostToolUse hooks detect violations in written code and prompt
|
|
11
|
+
* injection in read content, and scan context-mill skill downloads.
|
|
12
|
+
*/
|
|
13
|
+
type HookInput = Record<string, unknown>;
|
|
14
|
+
type HookOutput = Record<string, unknown>;
|
|
15
|
+
type HookCallback = (input: HookInput, toolUseID: string | undefined, options: {
|
|
16
|
+
signal: AbortSignal;
|
|
17
|
+
}) => Promise<HookOutput>;
|
|
18
|
+
export interface HookCallbackMatcher {
|
|
19
|
+
matcher?: string;
|
|
20
|
+
hooks: HookCallback[];
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Reset counters (for testing) */
|
|
24
|
+
export declare function resetScanReport(): void;
|
|
25
|
+
/** Format the scan report summary. Returns null if no scans occurred */
|
|
26
|
+
export declare function formatScanReport(): string | null;
|
|
27
|
+
/** Write the scan report to a JSON file. Returns the file path, or null if no scans occurred. */
|
|
28
|
+
export declare function writeScanReport(): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Create PreToolUse hook matchers for YARA scanning.
|
|
31
|
+
* Scans Bash commands before execution for exfiltration,
|
|
32
|
+
* destructive operations, and supply chain violations.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createPreToolUseYaraHooks(): HookCallbackMatcher[];
|
|
35
|
+
/**
|
|
36
|
+
* Create PostToolUse hook matchers for YARA scanning.
|
|
37
|
+
*
|
|
38
|
+
* Three matchers:
|
|
39
|
+
* 1. Write/Edit — scan written content for PII, secrets, config violations
|
|
40
|
+
* 2. Read/Grep — scan read content for prompt injection
|
|
41
|
+
* 3. Bash (skill install) — scan downloaded skill files for poisoned content
|
|
42
|
+
*/
|
|
43
|
+
export declare function createPostToolUseYaraHooks(): HookCallbackMatcher[];
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* YARA hook wiring for the Claude Agent SDK.
|
|
4
|
+
*
|
|
5
|
+
* Creates PreToolUse and PostToolUse hook callback arrays that
|
|
6
|
+
* integrate the YARA scanner into the wizard's agent loop. These
|
|
7
|
+
* hooks are registered in the SDK's query() options alongside the
|
|
8
|
+
* existing Stop hook.
|
|
9
|
+
*
|
|
10
|
+
* PreToolUse hooks block dangerous commands before execution.
|
|
11
|
+
* PostToolUse hooks detect violations in written code and prompt
|
|
12
|
+
* injection in read content, and scan context-mill skill downloads.
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.resetScanReport = resetScanReport;
|
|
19
|
+
exports.formatScanReport = formatScanReport;
|
|
20
|
+
exports.writeScanReport = writeScanReport;
|
|
21
|
+
exports.createPreToolUseYaraHooks = createPreToolUseYaraHooks;
|
|
22
|
+
exports.createPostToolUseYaraHooks = createPostToolUseYaraHooks;
|
|
23
|
+
const fs_1 = __importDefault(require("fs"));
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
26
|
+
const yara_scanner_1 = require("./yara-scanner");
|
|
27
|
+
const debug_1 = require("../utils/debug");
|
|
28
|
+
const analytics_1 = require("../utils/analytics");
|
|
29
|
+
const skill_install_1 = require("./skill-install");
|
|
30
|
+
let scanCount = 0;
|
|
31
|
+
const scanViolations = [];
|
|
32
|
+
function recordScan() {
|
|
33
|
+
scanCount++;
|
|
34
|
+
}
|
|
35
|
+
function recordViolation(entry) {
|
|
36
|
+
scanViolations.push(entry);
|
|
37
|
+
}
|
|
38
|
+
/** Reset counters (for testing) */
|
|
39
|
+
function resetScanReport() {
|
|
40
|
+
scanCount = 0;
|
|
41
|
+
scanViolations.length = 0;
|
|
42
|
+
}
|
|
43
|
+
/** Format the scan report summary. Returns null if no scans occurred */
|
|
44
|
+
function formatScanReport() {
|
|
45
|
+
if (scanCount === 0)
|
|
46
|
+
return null;
|
|
47
|
+
const lines = ['', '— YARA Scanner Summary —'];
|
|
48
|
+
const violationCount = scanViolations.length;
|
|
49
|
+
const cleanCount = scanCount - violationCount;
|
|
50
|
+
lines.push(`✓ ${scanCount} tool calls scanned, ${violationCount} violation${violationCount !== 1 ? 's' : ''} detected`);
|
|
51
|
+
if (violationCount > 0) {
|
|
52
|
+
lines.push('');
|
|
53
|
+
for (const v of scanViolations) {
|
|
54
|
+
const tag = v.action.toUpperCase();
|
|
55
|
+
lines.push(` [${tag}] ${v.rule} (${v.severity.toUpperCase()}) — ${v.phase}:${v.tool}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (cleanCount > 0) {
|
|
59
|
+
lines.push('');
|
|
60
|
+
lines.push(`No violations: ✓ ${cleanCount} clean scan${cleanCount !== 1 ? 's' : ''}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}
|
|
65
|
+
const YARA_REPORT_PATH = '/tmp/posthog-wizard-yara-report.json';
|
|
66
|
+
/** Write the scan report to a JSON file. Returns the file path, or null if no scans occurred. */
|
|
67
|
+
function writeScanReport() {
|
|
68
|
+
if (scanCount === 0)
|
|
69
|
+
return null;
|
|
70
|
+
const report = {
|
|
71
|
+
summary: {
|
|
72
|
+
totalScans: scanCount,
|
|
73
|
+
violations: scanViolations.length,
|
|
74
|
+
clean: scanCount - scanViolations.length,
|
|
75
|
+
},
|
|
76
|
+
violations: scanViolations,
|
|
77
|
+
};
|
|
78
|
+
try {
|
|
79
|
+
fs_1.default.writeFileSync(YARA_REPORT_PATH, JSON.stringify(report, null, 2));
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
(0, debug_1.logToFile)('[YARA] Failed to write scan report:', err);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return YARA_REPORT_PATH;
|
|
86
|
+
}
|
|
87
|
+
// ─── Hook Timeouts (ms) ─────────────────────────────────────────
|
|
88
|
+
/** Timeout for synchronous scan hooks (PreToolUse, PostToolUse Write/Edit/Read) */
|
|
89
|
+
const HOOK_TIMEOUT_MS = 60;
|
|
90
|
+
/** Timeout for skill install hook (involves filesystem I/O) */
|
|
91
|
+
const SKILL_SCAN_HOOK_TIMEOUT_MS = 120;
|
|
92
|
+
// ─── Logging ─────────────────────────────────────────────────────
|
|
93
|
+
function logYaraMatch(phase, tool, match, action) {
|
|
94
|
+
(0, debug_1.logToFile)(`[YARA] ${phase}:${tool} [${action.toUpperCase()}] rule "${match.rule.name}" ` +
|
|
95
|
+
`(severity: ${match.rule.severity}, category: ${match.rule.category})\n` +
|
|
96
|
+
` Description: ${match.rule.description}\n` +
|
|
97
|
+
` Matched text: "${match.matchedText.substring(0, 200)}"`);
|
|
98
|
+
analytics_1.analytics.wizardCapture('yara rule matched', {
|
|
99
|
+
rule: match.rule.name,
|
|
100
|
+
severity: match.rule.severity,
|
|
101
|
+
category: match.rule.category,
|
|
102
|
+
action,
|
|
103
|
+
phase,
|
|
104
|
+
tool,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// ─── Severity helpers ────────────────────────────────────────────
|
|
108
|
+
const SEVERITY_RANK = {
|
|
109
|
+
critical: 4,
|
|
110
|
+
high: 3,
|
|
111
|
+
medium: 2,
|
|
112
|
+
low: 1,
|
|
113
|
+
};
|
|
114
|
+
/** Return the highest-severity match from a list of matches. */
|
|
115
|
+
function highestSeverityMatch(matches) {
|
|
116
|
+
return matches.reduce((worst, m) => (SEVERITY_RANK[m.rule.severity] ?? 0) >
|
|
117
|
+
(SEVERITY_RANK[worst.rule.severity] ?? 0)
|
|
118
|
+
? m
|
|
119
|
+
: worst);
|
|
120
|
+
}
|
|
121
|
+
// ─── PreToolUse Hooks ────────────────────────────────────────────
|
|
122
|
+
/**
|
|
123
|
+
* Create PreToolUse hook matchers for YARA scanning.
|
|
124
|
+
* Scans Bash commands before execution for exfiltration,
|
|
125
|
+
* destructive operations, and supply chain violations.
|
|
126
|
+
*/
|
|
127
|
+
function createPreToolUseYaraHooks() {
|
|
128
|
+
return [
|
|
129
|
+
{
|
|
130
|
+
hooks: [
|
|
131
|
+
(input) => {
|
|
132
|
+
try {
|
|
133
|
+
const toolName = input.tool_name;
|
|
134
|
+
if (toolName !== 'Bash')
|
|
135
|
+
return Promise.resolve({});
|
|
136
|
+
const toolInput = input.tool_input;
|
|
137
|
+
const command = typeof toolInput?.command === 'string' ? toolInput.command : '';
|
|
138
|
+
if (!command)
|
|
139
|
+
return Promise.resolve({});
|
|
140
|
+
recordScan();
|
|
141
|
+
const result = (0, yara_scanner_1.scan)(command, 'PreToolUse', 'Bash');
|
|
142
|
+
if (!result.matched)
|
|
143
|
+
return Promise.resolve({});
|
|
144
|
+
const match = highestSeverityMatch(result.matches);
|
|
145
|
+
logYaraMatch('PreToolUse', 'Bash', match, 'blocked');
|
|
146
|
+
recordViolation({
|
|
147
|
+
rule: match.rule.name,
|
|
148
|
+
severity: match.rule.severity,
|
|
149
|
+
action: 'blocked',
|
|
150
|
+
phase: 'PreToolUse',
|
|
151
|
+
tool: 'Bash',
|
|
152
|
+
});
|
|
153
|
+
return Promise.resolve({
|
|
154
|
+
decision: 'block',
|
|
155
|
+
reason: `[YARA] ${match.rule.name}: ${match.rule.description}. Command blocked for security.`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
(0, debug_1.logToFile)('[YARA] PreToolUse hook error:', error);
|
|
160
|
+
// Fail closed: block the command if scanning fails
|
|
161
|
+
return Promise.resolve({
|
|
162
|
+
decision: 'block',
|
|
163
|
+
reason: '[YARA] Scanner error — command blocked as a precaution.',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
// ─── PostToolUse Hooks ───────────────────────────────────────────
|
|
173
|
+
/**
|
|
174
|
+
* Create PostToolUse hook matchers for YARA scanning.
|
|
175
|
+
*
|
|
176
|
+
* Three matchers:
|
|
177
|
+
* 1. Write/Edit — scan written content for PII, secrets, config violations
|
|
178
|
+
* 2. Read/Grep — scan read content for prompt injection
|
|
179
|
+
* 3. Bash (skill install) — scan downloaded skill files for poisoned content
|
|
180
|
+
*/
|
|
181
|
+
function createPostToolUseYaraHooks() {
|
|
182
|
+
return [
|
|
183
|
+
// ── Write/Edit content scanning ──
|
|
184
|
+
{
|
|
185
|
+
hooks: [
|
|
186
|
+
(input) => {
|
|
187
|
+
try {
|
|
188
|
+
const toolName = input.tool_name;
|
|
189
|
+
if (toolName !== 'Write' && toolName !== 'Edit')
|
|
190
|
+
return Promise.resolve({});
|
|
191
|
+
const toolInput = input.tool_input;
|
|
192
|
+
// For Write, scan the content being written
|
|
193
|
+
// For Edit, scan the new_str (replacement text)
|
|
194
|
+
const content = toolName === 'Write'
|
|
195
|
+
? toolInput?.content ?? ''
|
|
196
|
+
: toolInput?.new_str ?? '';
|
|
197
|
+
if (!content)
|
|
198
|
+
return Promise.resolve({});
|
|
199
|
+
recordScan();
|
|
200
|
+
const tool = toolName;
|
|
201
|
+
const result = (0, yara_scanner_1.scan)(content, 'PostToolUse', tool);
|
|
202
|
+
if (!result.matched)
|
|
203
|
+
return Promise.resolve({});
|
|
204
|
+
const match = highestSeverityMatch(result.matches);
|
|
205
|
+
logYaraMatch('PostToolUse', tool, match, 'reverted');
|
|
206
|
+
recordViolation({
|
|
207
|
+
rule: match.rule.name,
|
|
208
|
+
severity: match.rule.severity,
|
|
209
|
+
action: 'reverted',
|
|
210
|
+
phase: 'PostToolUse',
|
|
211
|
+
tool,
|
|
212
|
+
});
|
|
213
|
+
return Promise.resolve({
|
|
214
|
+
hookSpecificOutput: {
|
|
215
|
+
hookEventName: 'PostToolUse',
|
|
216
|
+
additionalContext: `[YARA VIOLATION] ${match.rule.name}: ${match.rule.description}. ` +
|
|
217
|
+
`You MUST revert this change immediately. The content you just wrote violates security policy.`,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
(0, debug_1.logToFile)('[YARA] PostToolUse Write/Edit hook error:', error);
|
|
223
|
+
// Fail closed: instruct the agent to revert if scanning fails
|
|
224
|
+
return Promise.resolve({
|
|
225
|
+
hookSpecificOutput: {
|
|
226
|
+
hookEventName: 'PostToolUse',
|
|
227
|
+
additionalContext: '[YARA] Scanner error — you MUST revert this change as a precaution.',
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
234
|
+
},
|
|
235
|
+
// ── Read/Grep prompt injection scanning ──
|
|
236
|
+
{
|
|
237
|
+
hooks: [
|
|
238
|
+
(input) => {
|
|
239
|
+
try {
|
|
240
|
+
const toolName = input.tool_name;
|
|
241
|
+
if (toolName !== 'Read' && toolName !== 'Grep')
|
|
242
|
+
return Promise.resolve({});
|
|
243
|
+
const toolResponse = input.tool_response;
|
|
244
|
+
const content = typeof toolResponse === 'string'
|
|
245
|
+
? toolResponse
|
|
246
|
+
: JSON.stringify(toolResponse ?? '');
|
|
247
|
+
if (!content)
|
|
248
|
+
return Promise.resolve({});
|
|
249
|
+
recordScan();
|
|
250
|
+
const tool = toolName;
|
|
251
|
+
const result = (0, yara_scanner_1.scan)(content, 'PostToolUse', tool);
|
|
252
|
+
if (!result.matched)
|
|
253
|
+
return Promise.resolve({});
|
|
254
|
+
const match = highestSeverityMatch(result.matches);
|
|
255
|
+
if (match.rule.severity === 'critical') {
|
|
256
|
+
logYaraMatch('PostToolUse', tool, match, 'aborted');
|
|
257
|
+
recordViolation({
|
|
258
|
+
rule: match.rule.name,
|
|
259
|
+
severity: match.rule.severity,
|
|
260
|
+
action: 'aborted',
|
|
261
|
+
phase: 'PostToolUse',
|
|
262
|
+
tool,
|
|
263
|
+
});
|
|
264
|
+
// Prompt injection: abort the session — context is poisoned
|
|
265
|
+
return Promise.resolve({
|
|
266
|
+
stopReason: `[YARA CRITICAL] ${match.rule.name}: Prompt injection detected in file content. ` +
|
|
267
|
+
`Agent context is potentially poisoned. Session terminated for safety.`,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
logYaraMatch('PostToolUse', tool, match, 'warned');
|
|
271
|
+
recordViolation({
|
|
272
|
+
rule: match.rule.name,
|
|
273
|
+
severity: match.rule.severity,
|
|
274
|
+
action: 'warned',
|
|
275
|
+
phase: 'PostToolUse',
|
|
276
|
+
tool,
|
|
277
|
+
});
|
|
278
|
+
return Promise.resolve({
|
|
279
|
+
hookSpecificOutput: {
|
|
280
|
+
hookEventName: 'PostToolUse',
|
|
281
|
+
additionalContext: `[YARA WARNING] ${match.rule.name}: ${match.rule.description}`,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
(0, debug_1.logToFile)('[YARA] PostToolUse Read/Grep hook error:', error);
|
|
287
|
+
// Fail closed: terminate session if scanning fails on read content
|
|
288
|
+
return Promise.resolve({
|
|
289
|
+
stopReason: '[YARA] Scanner error while scanning read content — session terminated as a precaution.',
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
295
|
+
},
|
|
296
|
+
// ── Context-mill skill install scanning ──
|
|
297
|
+
{
|
|
298
|
+
hooks: [
|
|
299
|
+
async (input) => {
|
|
300
|
+
try {
|
|
301
|
+
const toolName = input.tool_name;
|
|
302
|
+
if (toolName !== 'Bash')
|
|
303
|
+
return {};
|
|
304
|
+
const toolInput = input.tool_input;
|
|
305
|
+
const command = typeof toolInput?.command === 'string' ? toolInput.command : '';
|
|
306
|
+
// Only scan after skill install commands
|
|
307
|
+
if (!(0, skill_install_1.isSkillInstallCommand)(command))
|
|
308
|
+
return {};
|
|
309
|
+
// Extract skill directory from command
|
|
310
|
+
const dirMatch = command.match(/mkdir -p (.claude\/skills\/[^\s&]+)/);
|
|
311
|
+
if (!dirMatch)
|
|
312
|
+
return {};
|
|
313
|
+
const skillDir = dirMatch[1];
|
|
314
|
+
const cwd = input.cwd ?? process.cwd();
|
|
315
|
+
recordScan();
|
|
316
|
+
const result = await scanSkillFiles(cwd, skillDir);
|
|
317
|
+
if (!result.matched)
|
|
318
|
+
return {};
|
|
319
|
+
const match = highestSeverityMatch(result.matches);
|
|
320
|
+
logYaraMatch('PostToolUse', 'Bash (skill install)', match, 'aborted');
|
|
321
|
+
recordViolation({
|
|
322
|
+
rule: match.rule.name,
|
|
323
|
+
severity: match.rule.severity,
|
|
324
|
+
action: 'aborted',
|
|
325
|
+
phase: 'PostToolUse',
|
|
326
|
+
tool: 'Bash (skill)',
|
|
327
|
+
});
|
|
328
|
+
return {
|
|
329
|
+
stopReason: `[YARA CRITICAL] Poisoned skill detected in ${skillDir}: ${match.rule.name}. ` +
|
|
330
|
+
`The downloaded skill contains potential prompt injection. Session terminated for safety.`,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
(0, debug_1.logToFile)('[YARA] PostToolUse skill install hook error:', error);
|
|
335
|
+
// Fail closed: terminate if skill scanning fails
|
|
336
|
+
return {
|
|
337
|
+
stopReason: '[YARA] Scanner error while scanning skill files — session terminated as a precaution.',
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
timeout: SKILL_SCAN_HOOK_TIMEOUT_MS,
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
}
|
|
346
|
+
// ─── Skill File Scanner ──────────────────────────────────────────
|
|
347
|
+
/**
|
|
348
|
+
* Read and scan all text files in a skill directory for prompt injection.
|
|
349
|
+
*/
|
|
350
|
+
async function scanSkillFiles(cwd, skillDir) {
|
|
351
|
+
const absoluteDir = path_1.default.resolve(cwd, skillDir);
|
|
352
|
+
if (!fs_1.default.existsSync(absoluteDir)) {
|
|
353
|
+
(0, debug_1.logToFile)(`[YARA] Skill directory does not exist: ${absoluteDir}`);
|
|
354
|
+
return { matched: false };
|
|
355
|
+
}
|
|
356
|
+
const files = await (0, fast_glob_1.default)('**/*.{md,txt,yaml,yml,json,js,ts,py,rb,sh}', {
|
|
357
|
+
cwd: absoluteDir,
|
|
358
|
+
absolute: true,
|
|
359
|
+
});
|
|
360
|
+
const fileContents = [];
|
|
361
|
+
for (const filePath of files) {
|
|
362
|
+
try {
|
|
363
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
364
|
+
fileContents.push({ path: filePath, content });
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
(0, debug_1.logToFile)(`[YARA] Could not read skill file ${filePath}:`, err);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (fileContents.length === 0) {
|
|
371
|
+
(0, debug_1.logToFile)(`[YARA] No text files found in skill directory: ${absoluteDir}`);
|
|
372
|
+
return { matched: false };
|
|
373
|
+
}
|
|
374
|
+
(0, debug_1.logToFile)(`[YARA] Scanning ${fileContents.length} files in skill directory: ${skillDir}`);
|
|
375
|
+
return (0, yara_scanner_1.scanSkillDirectory)(fileContents);
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=yara-hooks.js.map
|