harness-evolve 1.0.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/LICENSE +21 -0
- package/README.md +254 -0
- package/dist/cli.js +1685 -0
- package/dist/cli.js.map +1 -0
- package/dist/delivery/run-evolve.d.ts +2 -0
- package/dist/delivery/run-evolve.js +2069 -0
- package/dist/delivery/run-evolve.js.map +1 -0
- package/dist/hooks/permission-request.d.ts +8 -0
- package/dist/hooks/permission-request.js +405 -0
- package/dist/hooks/permission-request.js.map +1 -0
- package/dist/hooks/post-tool-use-failure.d.ts +9 -0
- package/dist/hooks/post-tool-use-failure.js +437 -0
- package/dist/hooks/post-tool-use-failure.js.map +1 -0
- package/dist/hooks/post-tool-use.d.ts +9 -0
- package/dist/hooks/post-tool-use.js +441 -0
- package/dist/hooks/post-tool-use.js.map +1 -0
- package/dist/hooks/pre-tool-use.d.ts +8 -0
- package/dist/hooks/pre-tool-use.js +434 -0
- package/dist/hooks/pre-tool-use.js.map +1 -0
- package/dist/hooks/stop.d.ts +8 -0
- package/dist/hooks/stop.js +1609 -0
- package/dist/hooks/stop.js.map +1 -0
- package/dist/hooks/user-prompt-submit.d.ts +8 -0
- package/dist/hooks/user-prompt-submit.js +442 -0
- package/dist/hooks/user-prompt-submit.js.map +1 -0
- package/dist/index.d.ts +1029 -0
- package/dist/index.js +3131 -0
- package/dist/index.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/storage/counter.ts","../../src/schemas/counter.ts","../../src/storage/dirs.ts","../../src/storage/config.ts","../../src/schemas/config.ts","../../src/analysis/jsonl-reader.ts","../../src/analysis/schemas.ts","../../src/schemas/log-entry.ts","../../src/analysis/pre-processor.ts","../../src/analysis/environment-scanner.ts","../../src/analysis/classifiers/repeated-prompts.ts","../../src/analysis/classifiers/long-prompts.ts","../../src/analysis/classifiers/permission-patterns.ts","../../src/analysis/classifiers/code-corrections.ts","../../src/analysis/classifiers/personal-info.ts","../../src/analysis/classifiers/config-drift.ts","../../src/analysis/classifiers/ecosystem-adapter.ts","../../src/analysis/experience-level.ts","../../src/analysis/classifiers/onboarding.ts","../../src/analysis/classifiers/index.ts","../../src/schemas/recommendation.ts","../../src/analysis/analyzer.ts","../../src/analysis/outcome-tracker.ts","../../src/delivery/state.ts","../../src/schemas/delivery.ts","../../src/schemas/onboarding.ts","../../src/analysis/trigger.ts","../../src/delivery/renderer.ts","../../src/delivery/rotator.ts","../../src/delivery/notification.ts","../../src/delivery/auto-apply.ts","../../src/delivery/appliers/index.ts","../../src/delivery/appliers/settings-applier.ts","../../src/delivery/appliers/rule-applier.ts","../../src/delivery/appliers/hook-applier.ts","../../src/generators/schemas.ts","../../src/generators/hook-generator.ts","../../src/cli/utils.ts","../../src/delivery/appliers/claude-md-applier.ts","../../src/delivery/run-evolve.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { lock } from 'proper-lockfile';\nimport writeFileAtomic from 'write-file-atomic';\nimport { counterSchema, type Counter } from '../schemas/counter.js';\nimport { paths, ensureInit } from './dirs.js';\n\n/**\n * Read the current counter state from disk.\n * Returns defaults (total=0, session={}) if no counter file exists.\n */\nexport async function readCounter(): Promise<Counter> {\n await ensureInit();\n try {\n const raw = await readFile(paths.counter, 'utf-8');\n return counterSchema.parse(JSON.parse(raw));\n } catch {\n // File doesn't exist or invalid -- return defaults\n return {\n total: 0,\n session: {},\n last_updated: new Date().toISOString(),\n };\n }\n}\n\n/**\n * Atomically increment the interaction counter with cross-process safety.\n *\n * Uses proper-lockfile (mkdir-based, macOS-safe) for cross-process locking\n * and write-file-atomic for crash-safe writes inside the lock.\n *\n * Pattern: ensure-file -> lock -> read -> increment -> atomic-write -> unlock\n */\nexport async function incrementCounter(sessionId: string): Promise<number> {\n await ensureInit();\n\n // Ensure counter file exists before locking (proper-lockfile requires existing file)\n try {\n await readFile(paths.counter, 'utf-8');\n } catch {\n const initial: Counter = {\n total: 0,\n session: {},\n last_updated: new Date().toISOString(),\n };\n await writeFileAtomic(paths.counter, JSON.stringify(initial, null, 2));\n }\n\n const release = await lock(paths.counter, {\n retries: { retries: 50, minTimeout: 20, maxTimeout: 1000, randomize: true },\n stale: 10000, // Consider lock stale after 10 seconds\n });\n\n try {\n const raw = await readFile(paths.counter, 'utf-8');\n const data = counterSchema.parse(JSON.parse(raw));\n data.total += 1;\n data.session[sessionId] = (data.session[sessionId] ?? 0) + 1;\n data.last_updated = new Date().toISOString();\n await writeFileAtomic(paths.counter, JSON.stringify(data, null, 2));\n return data.total;\n } finally {\n await release();\n }\n}\n\n/**\n * Reset the counter to zero. Used for testing and post-analysis reset.\n */\nexport async function resetCounter(): Promise<void> {\n await ensureInit();\n const data: Counter = {\n total: 0,\n session: {},\n last_updated: new Date().toISOString(),\n };\n await writeFileAtomic(paths.counter, JSON.stringify(data, null, 2));\n}\n","import { z } from 'zod/v4';\n\nexport const counterSchema = z.object({\n total: z.number().default(0),\n session: z.record(z.string(), z.number()).default({}),\n last_analysis: z.iso.datetime().optional(),\n last_updated: z.iso.datetime(),\n});\nexport type Counter = z.infer<typeof counterSchema>;\n","import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nconst BASE_DIR = join(process.env.HOME ?? '', '.harness-evolve');\n\nexport const paths = {\n base: BASE_DIR,\n logs: {\n prompts: join(BASE_DIR, 'logs', 'prompts'),\n tools: join(BASE_DIR, 'logs', 'tools'),\n permissions: join(BASE_DIR, 'logs', 'permissions'),\n sessions: join(BASE_DIR, 'logs', 'sessions'),\n },\n analysis: join(BASE_DIR, 'analysis'),\n analysisPreProcessed: join(BASE_DIR, 'analysis', 'pre-processed'),\n summary: join(BASE_DIR, 'analysis', 'pre-processed', 'summary.json'),\n environmentSnapshot: join(BASE_DIR, 'analysis', 'environment-snapshot.json'),\n analysisResult: join(BASE_DIR, 'analysis', 'analysis-result.json'),\n pending: join(BASE_DIR, 'pending'),\n config: join(BASE_DIR, 'config.json'),\n counter: join(BASE_DIR, 'counter.json'),\n recommendations: join(BASE_DIR, 'recommendations.md'),\n recommendationState: join(BASE_DIR, 'analysis', 'recommendation-state.json'),\n recommendationArchive: join(BASE_DIR, 'analysis', 'recommendations-archive'),\n notificationFlag: join(BASE_DIR, 'analysis', 'has-pending-notifications'),\n autoApplyLog: join(BASE_DIR, 'analysis', 'auto-apply-log.jsonl'),\n outcomeHistory: join(BASE_DIR, 'analysis', 'outcome-history.jsonl'),\n} as const;\n\nlet initialized = false;\n\nexport async function ensureInit(): Promise<void> {\n if (initialized) return;\n await mkdir(paths.logs.prompts, { recursive: true });\n await mkdir(paths.logs.tools, { recursive: true });\n await mkdir(paths.logs.permissions, { recursive: true });\n await mkdir(paths.logs.sessions, { recursive: true });\n await mkdir(paths.analysis, { recursive: true });\n await mkdir(paths.analysisPreProcessed, { recursive: true });\n await mkdir(paths.pending, { recursive: true });\n await mkdir(paths.recommendationArchive, { recursive: true });\n initialized = true;\n}\n\n// For testing: reset the initialized flag\nexport function resetInit(): void {\n initialized = false;\n}\n","import { readFile } from 'node:fs/promises';\nimport writeFileAtomic from 'write-file-atomic';\nimport { configSchema, type Config } from '../schemas/config.js';\nimport { paths } from './dirs.js';\n\nexport async function loadConfig(): Promise<Config> {\n try {\n const raw = await readFile(paths.config, 'utf-8');\n return configSchema.parse(JSON.parse(raw));\n } catch {\n // File doesn't exist, is invalid JSON, or fails strict validation\n const defaults = configSchema.parse({});\n await writeFileAtomic(paths.config, JSON.stringify(defaults, null, 2));\n return defaults;\n }\n}\n","import { z } from 'zod/v4';\n\nexport const configSchema = z.object({\n version: z.number().default(1),\n analysis: z.object({\n threshold: z.number().min(1).default(50),\n enabled: z.boolean().default(true),\n classifierThresholds: z.record(z.string(), z.number()).default({}),\n }).default({ threshold: 50, enabled: true, classifierThresholds: {} }),\n hooks: z.object({\n capturePrompts: z.boolean().default(true),\n captureTools: z.boolean().default(true),\n capturePermissions: z.boolean().default(true),\n captureSessions: z.boolean().default(true),\n }).default({\n capturePrompts: true,\n captureTools: true,\n capturePermissions: true,\n captureSessions: true,\n }),\n scrubbing: z.object({\n enabled: z.boolean().default(true),\n highEntropyDetection: z.boolean().default(false),\n customPatterns: z.array(z.object({\n name: z.string(),\n regex: z.string(),\n replacement: z.string(),\n })).default([]),\n }).default({\n enabled: true,\n highEntropyDetection: false,\n customPatterns: [],\n }),\n delivery: z.object({\n stdoutInjection: z.boolean().default(true),\n maxTokens: z.number().default(200),\n fullAuto: z.boolean().default(false),\n maxRecommendationsInFile: z.number().default(20),\n archiveAfterDays: z.number().default(7),\n }).default({\n stdoutInjection: true,\n maxTokens: 200,\n fullAuto: false,\n maxRecommendationsInFile: 20,\n archiveAfterDays: 7,\n }),\n}).strict();\n\nexport type Config = z.infer<typeof configSchema>;\n","// Streaming JSONL reader with date-range filtering and schema validation.\n// Reads daily-rotated .jsonl log files (YYYY-MM-DD.jsonl) and returns\n// validated, typed entries. Malformed or schema-invalid lines are silently\n// skipped to ensure robustness against partial writes or corruption.\n\nimport { createReadStream } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { createInterface } from 'node:readline';\nimport { join } from 'node:path';\nimport type { z } from 'zod/v4';\n\n/**\n * Format a Date as YYYY-MM-DD for filename comparison.\n */\nfunction formatDate(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\n/**\n * Read and parse all JSONL entries from a log directory, optionally\n * filtered by date range. Files are read in chronological order\n * (sorted by YYYY-MM-DD filename).\n *\n * @param logDir - Directory containing YYYY-MM-DD.jsonl files\n * @param schema - Zod schema for parsing and type inference\n * @param options - Optional date range filter (inclusive boundaries)\n * @returns Array of validated, typed entries\n */\nexport async function readLogEntries<T>(\n logDir: string,\n schema: z.ZodType<T>,\n options?: { since?: Date; until?: Date },\n): Promise<T[]> {\n let fileNames: string[];\n try {\n fileNames = await readdir(logDir);\n } catch {\n // Directory does not exist or is unreadable\n return [];\n }\n\n // Keep only .jsonl files\n let jsonlFiles = fileNames.filter((f) => f.endsWith('.jsonl'));\n\n // Apply date range filtering based on filename (YYYY-MM-DD.jsonl)\n const sinceStr = options?.since ? formatDate(options.since) : undefined;\n const untilStr = options?.until ? formatDate(options.until) : undefined;\n\n if (sinceStr || untilStr) {\n jsonlFiles = jsonlFiles.filter((f) => {\n const dateStr = f.replace('.jsonl', '');\n if (sinceStr && dateStr < sinceStr) return false;\n if (untilStr && dateStr > untilStr) return false;\n return true;\n });\n }\n\n // Sort alphabetically for chronological order (YYYY-MM-DD sorts lexically)\n jsonlFiles.sort();\n\n const entries: T[] = [];\n\n for (const file of jsonlFiles) {\n const filePath = join(logDir, file);\n const rl = createInterface({\n input: createReadStream(filePath, 'utf-8'),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n try {\n const parsed = schema.parse(JSON.parse(line));\n entries.push(parsed);\n } catch {\n // Silently skip malformed JSON or schema validation failures\n }\n }\n }\n\n return entries;\n}\n","// Output schemas for analysis results.\n// Defines the shape of summary.json and environment-snapshot.json.\n\nimport { z } from 'zod/v4';\n\n// Summary schema: aggregated usage statistics from log pre-processing\nexport const summarySchema = z.object({\n generated_at: z.iso.datetime(),\n period: z.object({\n since: z.string(), // YYYY-MM-DD\n until: z.string(), // YYYY-MM-DD\n days: z.number(),\n }),\n stats: z.object({\n total_prompts: z.number(),\n total_tool_uses: z.number(),\n total_permissions: z.number(),\n unique_sessions: z.number(),\n }),\n top_repeated_prompts: z\n .array(\n z.object({\n prompt: z.string(),\n count: z.number(),\n sessions: z.number(),\n }),\n )\n .max(20),\n tool_frequency: z.array(\n z.object({\n tool_name: z.string(),\n count: z.number(),\n avg_duration_ms: z.number().optional(),\n }),\n ),\n permission_patterns: z.array(\n z.object({\n tool_name: z.string(),\n count: z.number(),\n sessions: z.number(),\n }),\n ),\n long_prompts: z\n .array(\n z.object({\n prompt_preview: z.string(),\n length: z.number(),\n count: z.number(),\n }),\n )\n .max(10),\n});\nexport type Summary = z.infer<typeof summarySchema>;\n\n// Environment snapshot schema: discovered tools, settings, and ecosystems\nexport const environmentSnapshotSchema = z.object({\n generated_at: z.iso.datetime(),\n claude_code: z.object({\n version: z.string(),\n version_known: z.boolean(),\n compatible: z.boolean(),\n }),\n settings: z.object({\n user: z.unknown().nullable(),\n project: z.unknown().nullable(),\n local: z.unknown().nullable(),\n }),\n installed_tools: z.object({\n plugins: z.array(\n z.object({\n name: z.string(),\n marketplace: z.string(),\n enabled: z.boolean(),\n scope: z.string(),\n capabilities: z.array(z.string()),\n }),\n ),\n skills: z.array(\n z.object({\n name: z.string(),\n scope: z.enum(['user', 'project']),\n }),\n ),\n rules: z.array(\n z.object({\n name: z.string(),\n scope: z.enum(['user', 'project']),\n }),\n ),\n hooks: z.array(\n z.object({\n event: z.string(),\n scope: z.enum(['user', 'project', 'local']),\n type: z.string(),\n }),\n ),\n claude_md: z.array(\n z.object({\n path: z.string(),\n exists: z.boolean(),\n }),\n ),\n }),\n detected_ecosystems: z.array(z.string()),\n});\nexport type EnvironmentSnapshot = z.infer<typeof environmentSnapshotSchema>;\n","import { z } from 'zod/v4';\n\nexport const promptEntrySchema = z.object({\n timestamp: z.iso.datetime(),\n session_id: z.string(),\n cwd: z.string(),\n prompt: z.string(),\n prompt_length: z.number(),\n transcript_path: z.string().optional(),\n});\nexport type PromptEntry = z.infer<typeof promptEntrySchema>;\n\nexport const toolEntrySchema = z.object({\n timestamp: z.iso.datetime(),\n session_id: z.string(),\n event: z.enum(['pre', 'post', 'failure']),\n tool_name: z.string(),\n input_summary: z.string().optional(),\n duration_ms: z.number().optional(),\n success: z.boolean().optional(),\n});\nexport type ToolEntry = z.infer<typeof toolEntrySchema>;\n\nexport const permissionEntrySchema = z.object({\n timestamp: z.iso.datetime(),\n session_id: z.string(),\n tool_name: z.string(),\n decision: z.enum(['approved', 'denied', 'unknown']),\n});\nexport type PermissionEntry = z.infer<typeof permissionEntrySchema>;\n\nexport const sessionEntrySchema = z.object({\n timestamp: z.iso.datetime(),\n session_id: z.string(),\n event: z.enum(['start', 'end']),\n cwd: z.string().optional(),\n});\nexport type SessionEntry = z.infer<typeof sessionEntrySchema>;\n","// Pre-processing pipeline: reads accumulated JSONL logs, computes frequency\n// counts with cross-session tracking, extracts top-N patterns, and writes\n// a compact summary.json under 50KB for the analysis agent's context window.\n\nimport { readLogEntries } from './jsonl-reader.js';\nimport { summarySchema, type Summary } from './schemas.js';\nimport {\n promptEntrySchema,\n toolEntrySchema,\n permissionEntrySchema,\n} from '../schemas/log-entry.js';\nimport type { PromptEntry, ToolEntry } from '../schemas/log-entry.js';\nimport { paths, ensureInit } from '../storage/dirs.js';\nimport writeFileAtomic from 'write-file-atomic';\n\nconst PROMPT_TRUNCATE_LEN = 100;\nconst LONG_PROMPT_THRESHOLD = 200; // word count\nconst DEFAULT_TOP_N = 20;\nconst DEFAULT_DAYS = 30;\nconst MAX_LONG_PROMPTS = 10;\n\n/**\n * Normalize a prompt string for deduplication:\n * trim, lowercase, collapse all whitespace to a single space.\n */\nfunction normalizePrompt(prompt: string): string {\n return prompt.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\n/**\n * Format a Date as YYYY-MM-DD.\n */\nfunction formatDate(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\n/**\n * Count items with cross-session tracking.\n * Returns a Map keyed by the normalized identifier with count and unique sessions.\n */\nfunction countWithSessions(\n items: Array<{ key: string; session: string }>,\n): Map<string, { count: number; sessions: Set<string> }> {\n const map = new Map<string, { count: number; sessions: Set<string> }>();\n for (const { key, session } of items) {\n const existing = map.get(key);\n if (existing) {\n existing.count += 1;\n existing.sessions.add(session);\n } else {\n map.set(key, { count: 1, sessions: new Set([session]) });\n }\n }\n return map;\n}\n\n/**\n * Compute tool frequency with average duration from 'post' events.\n */\nfunction computeToolFrequency(\n tools: ToolEntry[],\n): Summary['tool_frequency'] {\n const map = new Map<string, { count: number; durations: number[] }>();\n for (const entry of tools) {\n const existing = map.get(entry.tool_name);\n if (existing) {\n existing.count += 1;\n if (entry.event === 'post' && entry.duration_ms != null) {\n existing.durations.push(entry.duration_ms);\n }\n } else {\n const durations: number[] = [];\n if (entry.event === 'post' && entry.duration_ms != null) {\n durations.push(entry.duration_ms);\n }\n map.set(entry.tool_name, { count: 1, durations });\n }\n }\n\n return Array.from(map.entries())\n .map(([tool_name, { count, durations }]) => ({\n tool_name,\n count,\n avg_duration_ms:\n durations.length > 0\n ? Math.round(\n durations.reduce((sum, d) => sum + d, 0) / durations.length,\n )\n : undefined,\n }))\n .sort((a, b) => b.count - a.count);\n}\n\n/**\n * Detect long prompts (over LONG_PROMPT_THRESHOLD words).\n * Groups by normalized text, counts occurrences, returns top MAX_LONG_PROMPTS.\n */\nfunction detectLongPrompts(prompts: PromptEntry[]): Summary['long_prompts'] {\n const map = new Map<string, { length: number; count: number }>();\n for (const entry of prompts) {\n const words = entry.prompt.trim().split(/\\s+/);\n if (words.length <= LONG_PROMPT_THRESHOLD) continue;\n const key = normalizePrompt(entry.prompt);\n const existing = map.get(key);\n if (existing) {\n existing.count += 1;\n } else {\n map.set(key, { length: words.length, count: 1 });\n }\n }\n\n return Array.from(map.entries())\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, MAX_LONG_PROMPTS)\n .map(([normalized, { length, count }]) => ({\n prompt_preview: normalized.slice(0, PROMPT_TRUNCATE_LEN),\n length,\n count,\n }));\n}\n\n/**\n * Pre-process accumulated JSONL logs and produce a compact summary.\n *\n * Reads prompt, tool, and permission logs within the specified date range,\n * computes frequency counts with cross-session aggregation, and writes\n * the result atomically to paths.summary.\n *\n * @param options.since - Start of date range (defaults to 30 days ago)\n * @param options.until - End of date range (defaults to now)\n * @param options.topN - Max entries in top_repeated_prompts (defaults to 20)\n * @returns The validated Summary object\n */\nexport async function preProcess(options?: {\n since?: Date;\n until?: Date;\n topN?: number;\n}): Promise<Summary> {\n const until = options?.until ?? new Date();\n const since =\n options?.since ?? new Date(until.getTime() - DEFAULT_DAYS * 86_400_000);\n const topN = options?.topN ?? DEFAULT_TOP_N;\n\n // Read all log entries within the date range\n const [prompts, tools, permissions] = await Promise.all([\n readLogEntries(paths.logs.prompts, promptEntrySchema, { since, until }),\n readLogEntries(paths.logs.tools, toolEntrySchema, { since, until }),\n readLogEntries(paths.logs.permissions, permissionEntrySchema, {\n since,\n until,\n }),\n ]);\n\n // Unique sessions across all entry types\n const sessionSet = new Set<string>();\n for (const p of prompts) sessionSet.add(p.session_id);\n for (const t of tools) sessionSet.add(t.session_id);\n for (const perm of permissions) sessionSet.add(perm.session_id);\n\n // Prompt frequency with cross-session tracking\n const promptCounts = countWithSessions(\n prompts.map((p) => ({\n key: normalizePrompt(p.prompt),\n session: p.session_id,\n })),\n );\n\n const topRepeatedPrompts = Array.from(promptCounts.entries())\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, topN)\n .map(([key, { count, sessions }]) => ({\n prompt: key.slice(0, PROMPT_TRUNCATE_LEN),\n count,\n sessions: sessions.size,\n }));\n\n // Tool frequency with average duration\n const toolFrequency = computeToolFrequency(tools);\n\n // Permission patterns with cross-session tracking\n const permissionCounts = countWithSessions(\n permissions.map((p) => ({\n key: p.tool_name,\n session: p.session_id,\n })),\n );\n\n const permissionPatterns = Array.from(permissionCounts.entries())\n .sort((a, b) => b[1].count - a[1].count)\n .map(([tool_name, { count, sessions }]) => ({\n tool_name,\n count,\n sessions: sessions.size,\n }));\n\n // Long prompt detection\n const longPrompts = detectLongPrompts(prompts);\n\n // Construct and validate summary\n const summary: Summary = summarySchema.parse({\n generated_at: new Date().toISOString(),\n period: {\n since: formatDate(since),\n until: formatDate(until),\n days: DEFAULT_DAYS,\n },\n stats: {\n total_prompts: prompts.length,\n total_tool_uses: tools.length,\n total_permissions: permissions.length,\n unique_sessions: sessionSet.size,\n },\n top_repeated_prompts: topRepeatedPrompts,\n tool_frequency: toolFrequency,\n permission_patterns: permissionPatterns,\n long_prompts: longPrompts,\n });\n\n // Write atomically to disk\n await ensureInit();\n await writeFileAtomic(paths.summary, JSON.stringify(summary));\n\n return summary;\n}\n","// Environment scanner: discovers installed Claude Code tools via filesystem\n// scanning, reads settings at all scopes, detects Claude Code version, and\n// identifies ecosystem presence (GSD, Cog, etc.).\n\nimport { readdir, readFile, access } from 'node:fs/promises';\nimport { execFileSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { constants } from 'node:fs';\nimport writeFileAtomic from 'write-file-atomic';\nimport {\n environmentSnapshotSchema,\n type EnvironmentSnapshot,\n} from './schemas.js';\nimport { paths, ensureInit } from '../storage/dirs.js';\n\n// Version compatibility range -- tested and verified\nconst KNOWN_COMPATIBLE_MIN = '2.1.0';\nconst KNOWN_COMPATIBLE_MAX = '2.1.99';\n\n/**\n * Scan the user's environment to discover installed Claude Code tools,\n * settings, version info, and ecosystem presence. Writes the snapshot\n * atomically to paths.environmentSnapshot.\n *\n * @param cwd - Current working directory (project root)\n * @param home - User home directory (defaults to process.env.HOME)\n * @returns Validated EnvironmentSnapshot\n */\nexport async function scanEnvironment(\n cwd: string,\n home?: string,\n): Promise<EnvironmentSnapshot> {\n const homeDir = home ?? process.env.HOME ?? '';\n\n // Read all 3 settings files in parallel\n const [userSettings, projectSettings, localSettings] = await Promise.all([\n readSettingsSafe(join(homeDir, '.claude', 'settings.json')),\n readSettingsSafe(join(cwd, '.claude', 'settings.json')),\n readSettingsSafe(join(cwd, '.claude', 'settings.local.json')),\n ]);\n\n // Extract enabledPlugins from user settings if present\n const enabledPluginNames = extractEnabledPlugins(userSettings);\n\n // Run all discovery functions in parallel\n const [claudeVersion, plugins, skills, rules, hooks, claudeMds, ecosystems] =\n await Promise.all([\n Promise.resolve(detectClaudeCodeVersion()),\n discoverPlugins(homeDir, enabledPluginNames),\n discoverSkills(homeDir, cwd),\n discoverRules(cwd),\n Promise.resolve(\n discoverHooks(userSettings, projectSettings, localSettings),\n ),\n discoverClaudeMd(homeDir, cwd),\n detectEcosystems(cwd, homeDir),\n ]);\n\n const snapshot: EnvironmentSnapshot = {\n generated_at: new Date().toISOString(),\n claude_code: claudeVersion,\n settings: {\n user: userSettings,\n project: projectSettings,\n local: localSettings,\n },\n installed_tools: {\n plugins,\n skills,\n rules,\n hooks,\n claude_md: claudeMds,\n },\n detected_ecosystems: ecosystems,\n };\n\n // Validate against schema before writing\n const validated = environmentSnapshotSchema.parse(snapshot);\n\n // Write atomically to analysis directory\n await ensureInit();\n await writeFileAtomic(\n paths.environmentSnapshot,\n JSON.stringify(validated),\n );\n\n return validated;\n}\n\n// --- Internal helpers ---\n\n/**\n * Detect Claude Code version by running `claude --version`.\n * Returns { version, version_known, compatible }.\n */\nfunction detectClaudeCodeVersion(): EnvironmentSnapshot['claude_code'] {\n try {\n const output = execFileSync('claude', ['--version'], {\n timeout: 3000,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n const match = output.match(/^(\\d+\\.\\d+\\.\\d+)/);\n if (!match) {\n return { version: 'unknown', version_known: false, compatible: false };\n }\n\n const version = match[1];\n const compatible =\n compareSemver(version, KNOWN_COMPATIBLE_MIN) >= 0 &&\n compareSemver(version, KNOWN_COMPATIBLE_MAX) <= 0;\n\n return { version, version_known: true, compatible };\n } catch {\n return { version: 'unknown', version_known: false, compatible: false };\n }\n}\n\n/**\n * Safely read and parse a JSON settings file.\n * Returns parsed object or null if file is missing or invalid.\n */\nasync function readSettingsSafe(\n filePath: string,\n): Promise<unknown | null> {\n try {\n const raw = await readFile(filePath, 'utf-8');\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract enabled plugin names from user settings.\n */\nfunction extractEnabledPlugins(settings: unknown): string[] {\n if (!settings || typeof settings !== 'object') return [];\n const obj = settings as Record<string, unknown>;\n if (!Array.isArray(obj.enabledPlugins)) return [];\n\n return obj.enabledPlugins\n .map((p: unknown) => {\n if (typeof p === 'string') return p;\n if (p && typeof p === 'object' && 'name' in p) {\n return String((p as { name: unknown }).name);\n }\n return null;\n })\n .filter((n): n is string => n !== null);\n}\n\n/**\n * Discover installed plugins from ~/.claude/plugins/installed_plugins.json.\n * Cross-references with enabledPlugins from settings for accuracy.\n */\nasync function discoverPlugins(\n home: string,\n enabledPluginNames: string[],\n): Promise<EnvironmentSnapshot['installed_tools']['plugins']> {\n try {\n const pluginsFile = join(home, '.claude', 'plugins', 'installed_plugins.json');\n const raw = await readFile(pluginsFile, 'utf-8');\n const installed = JSON.parse(raw) as unknown[];\n\n if (!Array.isArray(installed)) return [];\n\n const plugins: EnvironmentSnapshot['installed_tools']['plugins'] = [];\n\n for (const entry of installed) {\n if (!entry || typeof entry !== 'object') continue;\n const plugin = entry as Record<string, unknown>;\n const name = String(plugin.name ?? '');\n const marketplace = String(plugin.marketplace ?? 'unknown');\n const scope = String(plugin.scope ?? 'user');\n const version = String(plugin.version ?? 'latest');\n\n const enabled = enabledPluginNames.includes(name);\n\n // Scan plugin cache for capabilities\n const capabilities = await scanPluginCapabilities(\n home,\n marketplace,\n name,\n version,\n );\n\n plugins.push({ name, marketplace, enabled, scope, capabilities });\n }\n\n return plugins;\n } catch {\n return [];\n }\n}\n\n/**\n * Scan plugin cache directory for capability subdirectories.\n */\nasync function scanPluginCapabilities(\n home: string,\n marketplace: string,\n pluginName: string,\n version: string,\n): Promise<string[]> {\n const knownCapabilities = ['commands', 'skills', 'hooks', 'agents'];\n const capabilities: string[] = [];\n\n try {\n const cacheDir = join(\n home, '.claude', 'plugins', 'cache',\n marketplace, pluginName, version,\n );\n const entries = await readdir(cacheDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && knownCapabilities.includes(entry.name)) {\n capabilities.push(entry.name);\n }\n }\n } catch {\n // Cache directory does not exist or is unreadable\n }\n\n return capabilities;\n}\n\n/**\n * Discover skill directories at user and project scopes.\n */\nasync function discoverSkills(\n home: string,\n cwd: string,\n): Promise<EnvironmentSnapshot['installed_tools']['skills']> {\n const skills: EnvironmentSnapshot['installed_tools']['skills'] = [];\n\n // User-scope skills: ~/.claude/skills/\n try {\n const userSkillsDir = join(home, '.claude', 'skills');\n const entries = await readdir(userSkillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n skills.push({ name: entry.name, scope: 'user' });\n }\n }\n } catch {\n // Directory does not exist\n }\n\n // Project-scope skills: {cwd}/.claude/skills/\n try {\n const projectSkillsDir = join(cwd, '.claude', 'skills');\n const entries = await readdir(projectSkillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n skills.push({ name: entry.name, scope: 'project' });\n }\n }\n } catch {\n // Directory does not exist\n }\n\n return skills;\n}\n\n/**\n * Discover rule directories at project scope.\n */\nasync function discoverRules(\n cwd: string,\n): Promise<EnvironmentSnapshot['installed_tools']['rules']> {\n const rules: EnvironmentSnapshot['installed_tools']['rules'] = [];\n\n try {\n const rulesDir = join(cwd, '.claude', 'rules');\n const entries = await readdir(rulesDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n rules.push({ name: entry.name, scope: 'project' });\n }\n }\n } catch {\n // Directory does not exist\n }\n\n return rules;\n}\n\n/**\n * Extract hook definitions from settings objects at all 3 scopes.\n */\nfunction discoverHooks(\n userSettings: unknown,\n projectSettings: unknown,\n localSettings: unknown,\n): EnvironmentSnapshot['installed_tools']['hooks'] {\n const hooks: EnvironmentSnapshot['installed_tools']['hooks'] = [];\n\n extractHooksFromSettings(userSettings, 'user', hooks);\n extractHooksFromSettings(projectSettings, 'project', hooks);\n extractHooksFromSettings(localSettings, 'local', hooks);\n\n return hooks;\n}\n\n/**\n * Extract hooks from a single settings object and append to the hooks array.\n */\nfunction extractHooksFromSettings(\n settings: unknown,\n scope: 'user' | 'project' | 'local',\n hooks: EnvironmentSnapshot['installed_tools']['hooks'],\n): void {\n if (!settings || typeof settings !== 'object') return;\n const obj = settings as Record<string, unknown>;\n if (!obj.hooks || typeof obj.hooks !== 'object') return;\n\n const hooksConfig = obj.hooks as Record<string, unknown>;\n for (const [event, defs] of Object.entries(hooksConfig)) {\n if (!Array.isArray(defs)) continue;\n for (const def of defs) {\n if (!def || typeof def !== 'object') continue;\n const hookDef = def as Record<string, unknown>;\n const type = String(hookDef.type ?? 'command');\n hooks.push({ event, scope, type });\n }\n }\n}\n\n/**\n * Discover CLAUDE.md files at common locations.\n */\nasync function discoverClaudeMd(\n home: string,\n cwd: string,\n): Promise<EnvironmentSnapshot['installed_tools']['claude_md']> {\n const locations = [\n join(cwd, 'CLAUDE.md'),\n join(cwd, '.claude', 'CLAUDE.md'),\n join(home, '.claude', 'CLAUDE.md'),\n ];\n\n const results: EnvironmentSnapshot['installed_tools']['claude_md'] = [];\n\n for (const path of locations) {\n let exists = false;\n try {\n await access(path, constants.F_OK);\n exists = true;\n } catch {\n // File does not exist\n }\n results.push({ path, exists });\n }\n\n return results;\n}\n\n/**\n * Detect known ecosystems by checking for characteristic directories.\n */\nasync function detectEcosystems(\n cwd: string,\n home: string,\n): Promise<string[]> {\n const ecosystems: string[] = [];\n\n // GSD: check for .planning/ directory\n try {\n await access(join(cwd, '.planning'), constants.F_OK);\n ecosystems.push('gsd');\n } catch {\n // No GSD detected\n }\n\n // Cog: check for 'cog' in ~/.claude/skills/\n try {\n const skillsDir = join(home, '.claude', 'skills');\n const entries = await readdir(skillsDir);\n if (entries.some((e) => e.toLowerCase().includes('cog'))) {\n ecosystems.push('cog');\n }\n } catch {\n // Skills directory does not exist\n }\n\n return ecosystems;\n}\n\n/**\n * Compare two semver strings (X.Y.Z format).\n * Returns -1, 0, or 1.\n */\nfunction compareSemver(a: string, b: string): number {\n const partsA = a.split('.').map(Number);\n const partsB = b.split('.').map(Number);\n\n for (let i = 0; i < 3; i++) {\n const numA = partsA[i] ?? 0;\n const numB = partsB[i] ?? 0;\n if (numA < numB) return -1;\n if (numA > numB) return 1;\n }\n\n return 0;\n}\n","// Classifier for repeated short prompts.\n// Detects prompts used multiple times across sessions and recommends\n// creating a hook for automation. Short = under 50 words.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n/**\n * Truncate a string to maxLen characters, adding ellipsis if truncated.\n */\nfunction truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 3) + '...';\n}\n\n/**\n * Classify repeated short prompts (< 50 words) as HOOK recommendations.\n *\n * HIGH confidence: count >= 10 AND sessions >= 3\n * MEDIUM confidence: count >= 5 (already past min threshold)\n *\n * Skips prompts with word count > 50 (handled by long-prompts classifier).\n */\nexport function classifyRepeatedPrompts(\n summary: Summary,\n _snapshot: EnvironmentSnapshot,\n config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n const threshold = config.thresholds.repeated_prompt_min_count;\n\n for (let i = 0; i < summary.top_repeated_prompts.length; i++) {\n const entry = summary.top_repeated_prompts[i];\n\n if (entry.count < threshold) continue;\n\n // Skip long prompts -- handled by long-prompts classifier\n const wordCount = entry.prompt.split(/\\s+/).length;\n if (wordCount > 50) continue;\n\n const confidence: 'HIGH' | 'MEDIUM' =\n entry.count >= config.thresholds.repeated_prompt_high_count &&\n entry.sessions >= config.thresholds.repeated_prompt_high_sessions\n ? 'HIGH'\n : 'MEDIUM';\n\n const truncatedPrompt = truncate(entry.prompt, 60);\n\n recommendations.push({\n id: `rec-repeated-${i}`,\n target: 'HOOK',\n confidence,\n pattern_type: 'repeated_prompt',\n title: `Repeated prompt: \"${truncatedPrompt}\"`,\n description: `This prompt has been used ${entry.count} times across ${entry.sessions} sessions. Consider creating a hook or alias to automate this.`,\n evidence: {\n count: entry.count,\n sessions: entry.sessions,\n examples: [entry.prompt],\n },\n suggested_action: `Create a UserPromptSubmit hook that detects \"${truncatedPrompt}\" and auto-executes the intended action.`,\n });\n }\n\n return recommendations;\n}\n","// Classifier for long repeated prompts.\n// Detects prompts with high word count that are repeated, and recommends\n// converting them into a reusable skill.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n/**\n * Classify long repeated prompts as SKILL recommendations.\n *\n * HIGH confidence: length >= 300 words AND count >= 3\n * MEDIUM confidence: length >= 200 words AND count >= 2 (past min thresholds)\n *\n * Skips entries below long_prompt_min_words or long_prompt_min_count.\n */\nexport function classifyLongPrompts(\n summary: Summary,\n _snapshot: EnvironmentSnapshot,\n config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n\n for (let i = 0; i < summary.long_prompts.length; i++) {\n const entry = summary.long_prompts[i];\n\n if (entry.length < config.thresholds.long_prompt_min_words) continue;\n if (entry.count < config.thresholds.long_prompt_min_count) continue;\n\n const confidence: 'HIGH' | 'MEDIUM' =\n entry.count >= config.thresholds.long_prompt_high_count &&\n entry.length >= config.thresholds.long_prompt_high_words\n ? 'HIGH'\n : 'MEDIUM';\n\n recommendations.push({\n id: `rec-long-${i}`,\n target: 'SKILL',\n confidence,\n pattern_type: 'long_prompt',\n title: `Long repeated prompt (${entry.length} words, ${entry.count}x)`,\n description: `A ${entry.length}-word prompt has been used ${entry.count} times. Consider converting it to a reusable skill.`,\n evidence: {\n count: entry.count,\n examples: [entry.prompt_preview],\n },\n suggested_action: 'Create a skill in .claude/skills/ that encapsulates this prompt as a reusable workflow.',\n });\n }\n\n return recommendations;\n}\n","// Classifier for permission approval patterns.\n// Detects tools that are frequently approved across multiple sessions\n// and recommends adding them to allowedTools in settings.json.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n/**\n * Classify permission approval patterns as SETTINGS recommendations.\n *\n * HIGH confidence: count >= 15 AND sessions >= 4\n * MEDIUM confidence: count >= 10 AND sessions >= 3 (past min thresholds)\n *\n * Skips entries below permission_approval_min_count or permission_approval_min_sessions.\n */\nexport function classifyPermissionPatterns(\n summary: Summary,\n _snapshot: EnvironmentSnapshot,\n config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n\n for (let i = 0; i < summary.permission_patterns.length; i++) {\n const entry = summary.permission_patterns[i];\n\n if (entry.count < config.thresholds.permission_approval_min_count) continue;\n if (entry.sessions < config.thresholds.permission_approval_min_sessions) continue;\n\n const confidence: 'HIGH' | 'MEDIUM' =\n entry.count >= config.thresholds.permission_approval_high_count &&\n entry.sessions >= config.thresholds.permission_approval_high_sessions\n ? 'HIGH'\n : 'MEDIUM';\n\n recommendations.push({\n id: `rec-permission-always-approved-${i}`,\n target: 'SETTINGS',\n confidence,\n pattern_type: 'permission-always-approved',\n title: `Frequently approved tool: ${entry.tool_name}`,\n description: `You have approved \"${entry.tool_name}\" ${entry.count} times across ${entry.sessions} sessions. Consider adding it to allowedTools in settings.json.`,\n evidence: {\n count: entry.count,\n sessions: entry.sessions,\n examples: [`${entry.tool_name} approved ${entry.count} times`],\n },\n suggested_action: `Add \"${entry.tool_name}\" to the \"allow\" array in ~/.claude/settings.json permissions.`,\n });\n }\n\n return recommendations;\n}\n","// Classifier for code correction patterns.\n// Detects high-usage code-modification tools (Write, Edit, MultiEdit) and\n// recommends creating rules to standardize recurring modification patterns.\n// This is a LOW-confidence heuristic: the summary pre-aggregates tool usage\n// without per-tool failure rates, so we use a simplified approach.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n// Tools that modify code -- high usage suggests recurring patterns\nconst CODE_MODIFICATION_TOOLS = new Set(['Write', 'Edit', 'MultiEdit']);\n\n// Minimum usage count to suggest rule creation (heuristic threshold)\nconst HIGH_USAGE_THRESHOLD = 20;\n\n/**\n * Classify code correction patterns as RULE recommendations.\n *\n * LOW confidence: code-modification tool count >= 20 uses.\n *\n * Since summary.tool_frequency does not track per-tool failure rates,\n * this classifier uses a simplified heuristic: tools that modify files\n * (Write, Edit, MultiEdit) with high usage counts are candidates for\n * coding rules or conventions.\n */\nexport function classifyCodeCorrections(\n summary: Summary,\n _snapshot: EnvironmentSnapshot,\n _config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n let index = 0;\n\n for (const entry of summary.tool_frequency) {\n // Only consider code-modification tools\n if (!CODE_MODIFICATION_TOOLS.has(entry.tool_name)) continue;\n\n // Require high usage count as a proxy for recurring patterns\n if (entry.count < HIGH_USAGE_THRESHOLD) continue;\n\n recommendations.push({\n id: `rec-correction-${index}`,\n target: 'RULE',\n confidence: 'LOW',\n pattern_type: 'code_correction',\n title: `Frequent code modifications with ${entry.tool_name} (${entry.count} uses)`,\n description: `The ${entry.tool_name} tool has been used ${entry.count} times. Review for recurring patterns that could become a coding rule or convention.`,\n evidence: {\n count: entry.count,\n examples: [entry.tool_name],\n },\n suggested_action: `Review recent ${entry.tool_name} usage for recurring patterns. If a consistent code style or approach emerges, create a rule in .claude/rules/.`,\n });\n\n index++;\n }\n\n return recommendations;\n}\n","// Classifier for personal information mentions.\n// Detects prompts containing personal keywords (name, location, preferences)\n// and recommends storing them in memory for automatic context.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n// Keywords that indicate personal information or preferences\nconst PERSONAL_KEYWORDS = [\n 'my name is',\n 'i live in',\n 'i work at',\n 'i prefer',\n 'my email',\n 'my project',\n 'always use',\n 'never use',\n];\n\n// Minimum repeat count to avoid flagging one-off mentions\nconst MIN_COUNT = 2;\n\n/**\n * Classify personal info mentions as MEMORY recommendations.\n *\n * LOW confidence for all matches -- keyword matching is inherently heuristic.\n *\n * Deduplicates by keyword: each keyword produces at most one recommendation,\n * using the first matching prompt as the example.\n */\nexport function classifyPersonalInfo(\n summary: Summary,\n _snapshot: EnvironmentSnapshot,\n _config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n const matchedKeywords = new Set<string>();\n let index = 0;\n\n for (const entry of summary.top_repeated_prompts) {\n if (entry.count < MIN_COUNT) continue;\n\n const lowerPrompt = entry.prompt.toLowerCase();\n\n for (const keyword of PERSONAL_KEYWORDS) {\n if (matchedKeywords.has(keyword)) continue;\n if (!lowerPrompt.includes(keyword)) continue;\n\n matchedKeywords.add(keyword);\n\n recommendations.push({\n id: `rec-personal-${index}`,\n target: 'MEMORY',\n confidence: 'LOW',\n pattern_type: 'personal_info',\n title: `Personal preference detected: \"${keyword}...\"`,\n description: `A prompt mentioning personal information (\"${keyword}\") has appeared ${entry.count} times. Consider storing this in memory for automatic context.`,\n evidence: {\n count: entry.count,\n sessions: entry.sessions,\n examples: [entry.prompt],\n },\n suggested_action: 'Add this information to memory (e.g., CLAUDE.md or a memory file) so Claude Code can use it without being reminded.',\n });\n\n index++;\n }\n }\n\n return recommendations;\n}\n","// Classifier for configuration drift detection.\n// Detects potential conflicts and redundancies in the user's Claude Code\n// configuration: hook-rule overlaps, multiple CLAUDE.md files, and\n// excessive hook counts.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n// Threshold for excessive hooks across all scopes\nconst MAX_HOOKS_BEFORE_REVIEW = 10;\n\n/**\n * Classify configuration drift patterns.\n *\n * All config drift recommendations are LOW confidence.\n *\n * Check 1: Hook-Rule overlap -- hooks and rules with matching names/events\n * suggest duplicated behavior that should be consolidated.\n * Check 2: Multiple CLAUDE.md -- multiple existing CLAUDE.md files may\n * contain contradictory instructions.\n * Check 3: Hook count heuristic -- more than 10 hooks suggests potential\n * redundancy that warrants review.\n */\nexport function classifyConfigDrift(\n _summary: Summary,\n snapshot: EnvironmentSnapshot,\n _config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n let index = 0;\n\n // Check 1: Hook-Rule overlap\n const hookEvents = new Set(snapshot.installed_tools.hooks.map(h => h.event));\n const ruleNames = new Set(snapshot.installed_tools.rules.map(r => r.name));\n\n for (const overlap of hookEvents) {\n if (!ruleNames.has(overlap)) continue;\n\n recommendations.push({\n id: `rec-drift-${index}`,\n target: 'RULE',\n confidence: 'LOW',\n pattern_type: 'config_drift',\n title: `Hook-rule overlap detected: \"${overlap}\"`,\n description: `Both a hook (event: \"${overlap}\") and a rule (name: \"${overlap}\") exist. This may indicate duplicated behavior that should be consolidated into one mechanism.`,\n evidence: {\n count: 2,\n examples: [`Hook event: ${overlap}`, `Rule name: ${overlap}`],\n },\n suggested_action: `Review the hook and rule for \"${overlap}\". If they serve the same purpose, consolidate into the more appropriate mechanism (hooks for 100% reliability, rules for guidance).`,\n });\n\n index++;\n }\n\n // Check 2: Multiple CLAUDE.md files\n const existingClaudeMd = snapshot.installed_tools.claude_md.filter(c => c.exists);\n if (existingClaudeMd.length > 1) {\n recommendations.push({\n id: `rec-drift-${index}`,\n target: 'CLAUDE_MD',\n confidence: 'LOW',\n pattern_type: 'config_drift',\n title: `Multiple CLAUDE.md files detected (${existingClaudeMd.length})`,\n description: `Found ${existingClaudeMd.length} existing CLAUDE.md files. Multiple CLAUDE.md files may contain contradictory instructions. Review for consistency.`,\n evidence: {\n count: existingClaudeMd.length,\n examples: existingClaudeMd.slice(0, 3).map(c => c.path),\n },\n suggested_action: 'Review all CLAUDE.md files for contradictions or redundancies. Consider consolidating shared instructions into the most appropriate scope.',\n });\n\n index++;\n }\n\n // Check 3: Hook count heuristic\n if (snapshot.installed_tools.hooks.length > MAX_HOOKS_BEFORE_REVIEW) {\n recommendations.push({\n id: `rec-drift-${index}`,\n target: 'HOOK',\n confidence: 'LOW',\n pattern_type: 'config_drift',\n title: `Excessive hook count (${snapshot.installed_tools.hooks.length} hooks)`,\n description: `Found ${snapshot.installed_tools.hooks.length} hooks across all scopes. This many hooks may indicate redundancy or performance concerns. Review for consolidation.`,\n evidence: {\n count: snapshot.installed_tools.hooks.length,\n examples: snapshot.installed_tools.hooks.slice(0, 3).map(h => `${h.event} (${h.scope})`),\n },\n suggested_action: 'Review all hooks for overlapping functionality. Consider combining hooks that trigger on the same event or serve similar purposes.',\n });\n }\n\n return recommendations;\n}\n","// Classifier for ecosystem-aware routing adaptations.\n// Produces recommendations based on detected ecosystems (GSD, Cog) and\n// Claude Code version compatibility. Enhances routing suggestions with\n// ecosystem-specific context.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\n\n// Minimum prompt repeat count to consider it a multi-step workflow candidate\nconst MULTI_STEP_MIN_COUNT = 3;\n\n/**\n * Classify ecosystem-specific adaptations and version recommendations.\n *\n * Version check (RTG-10): MEDIUM confidence when Claude Code version is\n * outside the tested compatible range.\n *\n * GSD ecosystem (RTG-09): LOW confidence SKILL recommendation when GSD\n * is detected and repeated multi-step prompts exist.\n *\n * Cog ecosystem (RTG-09): LOW confidence MEMORY recommendation when Cog\n * is detected, routing memory management to Cog tiers.\n */\nexport function classifyEcosystemAdaptations(\n summary: Summary,\n snapshot: EnvironmentSnapshot,\n _config: AnalysisConfig,\n): Recommendation[] {\n const recommendations: Recommendation[] = [];\n let index = 0;\n\n // Version check (RTG-10)\n if (\n snapshot.claude_code.version_known &&\n !snapshot.claude_code.compatible &&\n snapshot.claude_code.version !== 'unknown'\n ) {\n recommendations.push({\n id: `rec-ecosystem-${index}`,\n target: 'CLAUDE_MD',\n confidence: 'MEDIUM',\n pattern_type: 'version_update',\n title: `Claude Code version ${snapshot.claude_code.version} detected (outside tested range)`,\n description: `Your Claude Code version (${snapshot.claude_code.version}) is outside the tested compatible range. New features may be available that change optimal configuration strategies.`,\n evidence: {\n count: 1,\n examples: [`Version: ${snapshot.claude_code.version}`],\n },\n suggested_action: `Review Claude Code changelog for version ${snapshot.claude_code.version}. New hook events, permission models, or settings may require harness-evolve configuration updates.`,\n });\n index++;\n }\n\n // GSD ecosystem (RTG-09)\n if (snapshot.detected_ecosystems.includes('gsd')) {\n // Look for repeated multi-step prompts that could be GSD workflows\n const multiStepPrompts = summary.top_repeated_prompts.filter(\n p => p.count >= MULTI_STEP_MIN_COUNT,\n );\n\n if (multiStepPrompts.length > 0) {\n const topPrompt = multiStepPrompts[0];\n recommendations.push({\n id: `rec-ecosystem-${index}`,\n target: 'SKILL',\n confidence: 'LOW',\n pattern_type: 'ecosystem_gsd',\n title: 'GSD workflow detected -- consider /gsd slash commands',\n description: 'GSD is installed in this project. Repeated multi-step prompts may be better served by GSD planning phases or slash commands rather than standalone skills.',\n evidence: {\n count: multiStepPrompts.length,\n examples: [topPrompt.prompt],\n },\n suggested_action: 'Review repeated prompts and consider if they map to GSD phases (/gsd:plan-phase, /gsd:execute-phase) or custom slash commands.',\n ecosystem_context: 'GSD detected: Use /gsd slash commands and .planning patterns for multi-step workflows instead of standalone skills',\n });\n index++;\n }\n }\n\n // Cog ecosystem (RTG-09)\n if (snapshot.detected_ecosystems.includes('cog')) {\n recommendations.push({\n id: `rec-ecosystem-${index}`,\n target: 'MEMORY',\n confidence: 'LOW',\n pattern_type: 'ecosystem_cog',\n title: 'Cog memory system detected -- route memory to Cog tiers',\n description: \"Cog is installed. Personal information and contextual preferences should be routed to Cog's tiered memory system rather than raw CLAUDE.md entries.\",\n evidence: {\n count: 1,\n examples: ['Cog detected in ~/.claude/skills/'],\n },\n suggested_action: 'Use /reflect and /evolve Cog commands for memory management instead of manually editing CLAUDE.md.',\n ecosystem_context: 'Cog detected: Route memory entries to Cog tiers (/reflect, /evolve) instead of raw CLAUDE.md',\n });\n }\n\n return recommendations;\n}\n","// Pure function to compute user experience level from environment snapshot.\n// Scores each tool category by weight and maps total score to a tier:\n// 0 -> newcomer, 1-29 -> intermediate, 30+ -> power_user.\n// Weights reflect automation investment: plugins (10), hooks (8), ecosystems (7),\n// rules (6), skills (5), claude_md (3).\n\nimport type { EnvironmentSnapshot } from './schemas.js';\nimport type { ExperienceLevel, ExperienceTier } from '../schemas/onboarding.js';\n\nexport function computeExperienceLevel(snapshot: EnvironmentSnapshot): ExperienceLevel {\n const hooks = snapshot.installed_tools.hooks.length;\n const rules = snapshot.installed_tools.rules.length;\n const skills = snapshot.installed_tools.skills.length;\n const plugins = snapshot.installed_tools.plugins.length;\n const claudeMd = snapshot.installed_tools.claude_md.filter(c => c.exists).length;\n const ecosystems = snapshot.detected_ecosystems.length;\n\n const score = Math.min(100,\n hooks * 8 + rules * 6 + skills * 5 +\n plugins * 10 + claudeMd * 3 + ecosystems * 7,\n );\n\n const tier: ExperienceTier =\n score === 0 ? 'newcomer' :\n score < 30 ? 'intermediate' :\n 'power_user';\n\n return {\n tier,\n score,\n breakdown: { hooks, rules, skills, plugins, claude_md: claudeMd, ecosystems },\n };\n}\n","// Classifier for tiered onboarding detection.\n// Produces tier-appropriate recommendations based on user experience level:\n// newcomer (score=0) gets \"start here\" guidance for missing config,\n// power_user (score>=30) gets \"optimize\" suggestions,\n// intermediate (1-29) gets no onboarding-specific recs (handled by other classifiers).\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\nimport { computeExperienceLevel } from '../experience-level.js';\n\n/**\n * Classify onboarding needs based on user experience tier.\n *\n * Newcomer (score=0): Up to 3 MEDIUM-confidence \"start here\" recommendations\n * for missing hooks, rules, and CLAUDE.md.\n *\n * Power user (score>=30): 1 LOW-confidence \"optimize\" recommendation\n * suggesting consolidation review.\n *\n * Intermediate (1-29): No recommendations (existing classifiers handle\n * pattern-specific suggestions).\n */\nexport function classifyOnboarding(\n _summary: Summary,\n snapshot: EnvironmentSnapshot,\n _config: AnalysisConfig,\n): Recommendation[] {\n const level = computeExperienceLevel(snapshot);\n const recommendations: Recommendation[] = [];\n let index = 0;\n\n if (level.tier === 'newcomer') {\n // Suggest missing hooks\n if (level.breakdown.hooks === 0) {\n recommendations.push({\n id: `rec-onboarding-${index}`,\n target: 'HOOK',\n confidence: 'MEDIUM',\n pattern_type: 'onboarding_start_hooks',\n title: 'Start automating: create your first hook',\n description:\n 'Hooks run automatically on Claude Code lifecycle events (pre-commit, tool use, session start). ' +\n 'Start with a formatting or test-on-save hook to experience automation benefits.',\n evidence: {\n count: 0,\n examples: ['No hooks detected in your environment'],\n },\n suggested_action:\n 'Add a hook in .claude/settings.json hooks section for automation.',\n });\n index++;\n }\n\n // Suggest missing rules\n if (level.breakdown.rules === 0) {\n recommendations.push({\n id: `rec-onboarding-${index}`,\n target: 'RULE',\n confidence: 'MEDIUM',\n pattern_type: 'onboarding_start_rules',\n title: 'Define coding preferences: add your first rule',\n description:\n 'Rules (.claude/rules/) codify conventions that Claude follows automatically. ' +\n 'They persist across sessions and ensure consistent behavior.',\n evidence: {\n count: 0,\n examples: ['No rules detected in your environment'],\n },\n suggested_action:\n 'Create .claude/rules/ directory with a rule for your preferred coding style.',\n });\n index++;\n }\n\n // Suggest missing CLAUDE.md\n if (level.breakdown.claude_md === 0) {\n recommendations.push({\n id: `rec-onboarding-${index}`,\n target: 'CLAUDE_MD',\n confidence: 'MEDIUM',\n pattern_type: 'onboarding_start_claudemd',\n title: 'Set project context: create CLAUDE.md',\n description:\n 'CLAUDE.md gives Claude project-specific context — tech stack, conventions, and constraints. ' +\n 'It is loaded automatically at the start of every conversation.',\n evidence: {\n count: 0,\n examples: ['No CLAUDE.md files detected in your environment'],\n },\n suggested_action:\n 'Create CLAUDE.md in your project root with project description and conventions.',\n });\n }\n } else if (level.tier === 'power_user') {\n recommendations.push({\n id: 'rec-onboarding-3',\n target: 'SETTINGS',\n confidence: 'LOW',\n pattern_type: 'onboarding_optimize',\n title: 'Consider mechanizing recurring patterns',\n description:\n 'Your extensive configuration suggests active automation investment. ' +\n 'Review for redundancy or upgrade opportunities — hooks and rules with overlapping concerns can be consolidated.',\n evidence: {\n count: level.score,\n examples: [\n `${level.breakdown.hooks} hooks, ${level.breakdown.rules} rules, ${level.breakdown.plugins} plugins installed`,\n ],\n },\n suggested_action:\n 'Review your hooks and rules for overlapping concerns that could be consolidated.',\n });\n }\n // Intermediate: return empty array\n\n return recommendations;\n}\n","// Classifier registry: defines the Classifier type and holds all registered\n// classifier functions. New classifiers are added by importing and pushing\n// to the classifiers array.\n\nimport type { Summary, EnvironmentSnapshot } from '../schemas.js';\nimport type { Recommendation, AnalysisConfig } from '../../schemas/recommendation.js';\nimport { classifyRepeatedPrompts } from './repeated-prompts.js';\nimport { classifyLongPrompts } from './long-prompts.js';\nimport { classifyPermissionPatterns } from './permission-patterns.js';\nimport { classifyCodeCorrections } from './code-corrections.js';\nimport { classifyPersonalInfo } from './personal-info.js';\nimport { classifyConfigDrift } from './config-drift.js';\nimport { classifyEcosystemAdaptations } from './ecosystem-adapter.js';\nimport { classifyOnboarding } from './onboarding.js';\n\nexport type Classifier = (\n summary: Summary,\n snapshot: EnvironmentSnapshot,\n config: AnalysisConfig,\n) => Recommendation[];\n\n// Registered classifiers, evaluated in order by the analyzer\nexport const classifiers: Classifier[] = [\n classifyRepeatedPrompts,\n classifyLongPrompts,\n classifyPermissionPatterns,\n classifyCodeCorrections,\n classifyPersonalInfo,\n classifyConfigDrift,\n classifyEcosystemAdaptations,\n classifyOnboarding,\n];\n","// Recommendation and analysis result schemas.\n// Defines the output contracts for the analysis engine: routing targets,\n// confidence tiers, recommendation structure, and analysis configuration.\n\nimport { z } from 'zod/v4';\n\nexport const routingTargetSchema = z.enum([\n 'HOOK',\n 'SKILL',\n 'RULE',\n 'CLAUDE_MD',\n 'MEMORY',\n 'SETTINGS',\n]);\nexport type RoutingTarget = z.infer<typeof routingTargetSchema>;\n\nexport const confidenceSchema = z.enum(['HIGH', 'MEDIUM', 'LOW']);\nexport type Confidence = z.infer<typeof confidenceSchema>;\n\nexport const patternTypeSchema = z.enum([\n 'repeated_prompt',\n 'long_prompt',\n 'permission-always-approved',\n 'code_correction',\n 'personal_info',\n 'config_drift',\n 'version_update',\n 'ecosystem_gsd',\n 'ecosystem_cog',\n 'onboarding_start_hooks',\n 'onboarding_start_rules',\n 'onboarding_start_claudemd',\n 'onboarding_optimize',\n 'scan_redundancy',\n 'scan_missing_mechanization',\n 'scan_stale_reference',\n]);\nexport type PatternType = z.infer<typeof patternTypeSchema>;\n\nexport const recommendationSchema = z.object({\n id: z.string(),\n target: routingTargetSchema,\n confidence: confidenceSchema,\n pattern_type: patternTypeSchema,\n title: z.string(),\n description: z.string(),\n evidence: z.object({\n count: z.number(),\n sessions: z.number().optional(),\n examples: z.array(z.string()).max(3),\n }),\n suggested_action: z.string(),\n ecosystem_context: z.string().optional(),\n});\nexport type Recommendation = z.infer<typeof recommendationSchema>;\n\n// Default threshold values for classifiers\nconst DEFAULT_THRESHOLDS = {\n repeated_prompt_min_count: 5,\n repeated_prompt_high_count: 10,\n repeated_prompt_high_sessions: 3,\n repeated_prompt_medium_sessions: 2,\n long_prompt_min_words: 200,\n long_prompt_min_count: 2,\n long_prompt_high_words: 300,\n long_prompt_high_count: 3,\n permission_approval_min_count: 10,\n permission_approval_min_sessions: 3,\n permission_approval_high_count: 15,\n permission_approval_high_sessions: 4,\n code_correction_min_failure_rate: 0.3,\n code_correction_min_failures: 3,\n} as const;\n\nexport const analysisConfigSchema = z.object({\n thresholds: z.object({\n repeated_prompt_min_count: z.number().default(DEFAULT_THRESHOLDS.repeated_prompt_min_count),\n repeated_prompt_high_count: z.number().default(DEFAULT_THRESHOLDS.repeated_prompt_high_count),\n repeated_prompt_high_sessions: z.number().default(DEFAULT_THRESHOLDS.repeated_prompt_high_sessions),\n repeated_prompt_medium_sessions: z.number().default(DEFAULT_THRESHOLDS.repeated_prompt_medium_sessions),\n long_prompt_min_words: z.number().default(DEFAULT_THRESHOLDS.long_prompt_min_words),\n long_prompt_min_count: z.number().default(DEFAULT_THRESHOLDS.long_prompt_min_count),\n long_prompt_high_words: z.number().default(DEFAULT_THRESHOLDS.long_prompt_high_words),\n long_prompt_high_count: z.number().default(DEFAULT_THRESHOLDS.long_prompt_high_count),\n permission_approval_min_count: z.number().default(DEFAULT_THRESHOLDS.permission_approval_min_count),\n permission_approval_min_sessions: z.number().default(DEFAULT_THRESHOLDS.permission_approval_min_sessions),\n permission_approval_high_count: z.number().default(DEFAULT_THRESHOLDS.permission_approval_high_count),\n permission_approval_high_sessions: z.number().default(DEFAULT_THRESHOLDS.permission_approval_high_sessions),\n code_correction_min_failure_rate: z.number().default(DEFAULT_THRESHOLDS.code_correction_min_failure_rate),\n code_correction_min_failures: z.number().default(DEFAULT_THRESHOLDS.code_correction_min_failures),\n }).default(() => ({ ...DEFAULT_THRESHOLDS })),\n max_recommendations: z.number().default(20),\n}).default(() => ({\n thresholds: { ...DEFAULT_THRESHOLDS },\n max_recommendations: 20,\n}));\nexport type AnalysisConfig = z.infer<typeof analysisConfigSchema>;\n\nexport const analysisResultSchema = z.object({\n generated_at: z.iso.datetime(),\n summary_period: z.object({\n since: z.string(),\n until: z.string(),\n days: z.number(),\n }),\n recommendations: z.array(recommendationSchema),\n metadata: z.object({\n classifier_count: z.number(),\n patterns_evaluated: z.number(),\n environment_ecosystems: z.array(z.string()),\n claude_code_version: z.string(),\n }),\n});\nexport type AnalysisResult = z.infer<typeof analysisResultSchema>;\n","// Main analysis orchestrator: iterates all registered classifiers,\n// collects recommendations, sorts by confidence and evidence, caps\n// at max_recommendations, and returns a validated AnalysisResult.\n\nimport { classifiers } from './classifiers/index.js';\nimport type { Summary, EnvironmentSnapshot } from './schemas.js';\nimport {\n analysisConfigSchema,\n analysisResultSchema,\n type AnalysisConfig,\n type AnalysisResult,\n type Recommendation,\n} from '../schemas/recommendation.js';\nimport type { OutcomeSummary } from '../schemas/onboarding.js';\n\n// Confidence tier numeric ordering for sorting (ascending = higher priority)\nconst CONFIDENCE_ORDER: Record<string, number> = {\n HIGH: 0,\n MEDIUM: 1,\n LOW: 2,\n};\n\n/**\n * Sort recommendations by confidence (HIGH first), then by evidence.count\n * descending within the same tier.\n */\nfunction sortRecommendations(a: Recommendation, b: Recommendation): number {\n const confDiff =\n (CONFIDENCE_ORDER[a.confidence] ?? 3) -\n (CONFIDENCE_ORDER[b.confidence] ?? 3);\n if (confDiff !== 0) return confDiff;\n return b.evidence.count - a.evidence.count;\n}\n\n/**\n * Adjust recommendation confidence based on historical outcome data.\n * Pattern types with >30% revert rate (persistence_rate < 0.7) get\n * downgraded by one tier: HIGH->MEDIUM, MEDIUM->LOW, LOW stays LOW.\n */\nexport function adjustConfidence(\n recommendations: Recommendation[],\n summaries: OutcomeSummary[],\n): Recommendation[] {\n const rateByType = new Map(\n summaries.map((s) => [s.pattern_type, s.persistence_rate]),\n );\n\n return recommendations.map((rec) => {\n const rate = rateByType.get(rec.pattern_type);\n if (rate === undefined || rate >= 0.7) return rec;\n\n // Downgrade one tier\n const downgraded: Record<string, string> = {\n HIGH: 'MEDIUM',\n MEDIUM: 'LOW',\n LOW: 'LOW',\n };\n\n return {\n ...rec,\n confidence: (downgraded[rec.confidence] ??\n rec.confidence) as Recommendation['confidence'],\n };\n });\n}\n\n/**\n * Analyze a pre-processed summary and environment snapshot to produce\n * structured recommendations.\n *\n * @param summary - Pre-processed usage summary from pre-processor\n * @param snapshot - Environment snapshot from environment-scanner\n * @param config - Optional analysis configuration (defaults applied if omitted)\n * @param outcomeSummaries - Optional outcome summaries for confidence adjustment\n * @returns Validated AnalysisResult with sorted, capped recommendations\n */\nexport function analyze(\n summary: Summary,\n snapshot: EnvironmentSnapshot,\n config?: AnalysisConfig,\n outcomeSummaries?: OutcomeSummary[],\n): AnalysisResult {\n const mergedConfig = config ?? analysisConfigSchema.parse({});\n\n // Collect recommendations from all classifiers\n const recommendations: Recommendation[] = [];\n for (const classify of classifiers) {\n const results = classify(summary, snapshot, mergedConfig);\n recommendations.push(...results);\n }\n\n // Adjust confidence based on outcome history (if provided)\n const adjusted =\n outcomeSummaries && outcomeSummaries.length > 0\n ? adjustConfidence(recommendations, outcomeSummaries)\n : recommendations;\n\n // Sort by confidence tier, then by evidence count\n adjusted.sort(sortRecommendations);\n\n // Cap at max_recommendations\n const capped = adjusted.slice(0, mergedConfig.max_recommendations);\n\n // Compute patterns_evaluated as sum of all pattern source arrays\n const patternsEvaluated =\n summary.top_repeated_prompts.length +\n summary.long_prompts.length +\n summary.permission_patterns.length +\n summary.tool_frequency.length;\n\n return analysisResultSchema.parse({\n generated_at: new Date().toISOString(),\n summary_period: summary.period,\n recommendations: capped,\n metadata: {\n classifier_count: classifiers.length,\n patterns_evaluated: patternsEvaluated,\n environment_ecosystems: snapshot.detected_ecosystems,\n claude_code_version: snapshot.claude_code.version,\n },\n });\n}\n","// Outcome tracker: cross-references applied recommendations against\n// the current environment snapshot to determine whether changes persist.\n// Persists outcomes as JSONL and computes pattern-level summaries for\n// confidence adjustment in subsequent analysis runs.\n\nimport { readFile, appendFile } from 'node:fs/promises';\nimport { paths } from '../storage/dirs.js';\nimport { loadState } from '../delivery/state.js';\nimport {\n outcomeEntrySchema,\n type OutcomeEntry,\n type OutcomeSummary,\n} from '../schemas/onboarding.js';\nimport type { RecommendationStateEntry } from '../schemas/delivery.js';\nimport type { EnvironmentSnapshot } from './schemas.js';\n\n/**\n * Track outcomes for all applied recommendations by checking their\n * persistence in the current environment snapshot.\n *\n * For each applied recommendation:\n * 1. Check if the change still exists in the environment\n * 2. Determine outcome: positive (persisted 5+ checks), negative (reverted),\n * or monitoring (persisted but < 5 checks)\n * 3. Append outcome entry to JSONL history\n *\n * @param snapshot - Current environment snapshot\n * @returns Array of outcome entries for all applied recommendations\n */\nexport async function trackOutcomes(\n snapshot: EnvironmentSnapshot,\n): Promise<OutcomeEntry[]> {\n const state = await loadState();\n const applied = state.entries.filter((e) => e.status === 'applied');\n\n if (applied.length === 0) return [];\n\n const history = await loadOutcomeHistory();\n const results: OutcomeEntry[] = [];\n\n for (const entry of applied) {\n // Find most recent outcome for this recommendation\n const priorEntries = history.filter(\n (h) => h.recommendation_id === entry.id,\n );\n const latest = priorEntries.length > 0\n ? priorEntries[priorEntries.length - 1]\n : undefined;\n\n const checksCount = latest\n ? latest.checks_since_applied + 1\n : 1;\n\n const persisted = checkPersistence(entry, snapshot);\n\n // Determine outcome\n let outcome: 'positive' | 'negative' | 'monitoring';\n if (!persisted) {\n outcome = 'negative';\n } else if (checksCount >= 5) {\n outcome = 'positive';\n } else {\n outcome = 'monitoring';\n }\n\n // Infer pattern_type from the recommendation ID prefix\n const patternType = inferPatternType(entry.id);\n\n // Infer target from the recommendation ID prefix\n const target = inferTarget(entry.id);\n\n const outcomeEntry: OutcomeEntry = {\n recommendation_id: entry.id,\n pattern_type: patternType,\n target,\n applied_at: entry.updated_at,\n checked_at: new Date().toISOString(),\n persisted,\n checks_since_applied: checksCount,\n outcome,\n };\n\n results.push(outcomeEntry);\n await appendOutcome(outcomeEntry);\n }\n\n return results;\n}\n\n/**\n * Check whether an applied recommendation's change still persists\n * in the current environment.\n *\n * Detection heuristics by recommendation type:\n * - SETTINGS (allowedTools): check if tool exists in snapshot settings\n * - HOOK (rec-repeated-*): check if hooks exist in snapshot\n * - SKILL (rec-long-*): check if skills exist in snapshot\n * - RULE (rec-correction-*): check if rules exist in snapshot\n * - Default: assume persisted when persistence cannot be verified\n */\nfunction checkPersistence(\n entry: RecommendationStateEntry,\n snapshot: EnvironmentSnapshot,\n): boolean {\n // SETTINGS persistence: check allowedTools\n if (entry.applied_details) {\n const toolMatch = entry.applied_details.match(/Added (\\w+) to allowedTools/);\n if (toolMatch) {\n const toolName = toolMatch[1];\n const userSettings = snapshot.settings.user as Record<string, unknown> | null;\n if (!userSettings) return false;\n const allowedTools = userSettings.allowedTools;\n if (!Array.isArray(allowedTools)) return false;\n return allowedTools.includes(toolName);\n }\n }\n\n // HOOK persistence: rec-repeated-* prefix\n if (entry.id.startsWith('rec-repeated-')) {\n return snapshot.installed_tools.hooks.length > 0;\n }\n\n // SKILL persistence: rec-long-* prefix\n if (entry.id.startsWith('rec-long-')) {\n return snapshot.installed_tools.skills.length > 0;\n }\n\n // RULE persistence: rec-correction-* prefix\n if (entry.id.startsWith('rec-correction-')) {\n return snapshot.installed_tools.rules.length > 0;\n }\n\n // Default: assume persisted when we cannot verify\n return true;\n}\n\n/**\n * Append an outcome entry to the JSONL history file.\n */\nasync function appendOutcome(entry: OutcomeEntry): Promise<void> {\n await appendFile(\n paths.outcomeHistory,\n JSON.stringify(entry) + '\\n',\n 'utf-8',\n );\n}\n\n/**\n * Load outcome history from the JSONL file.\n * Returns empty array when the file does not exist.\n * Silently skips invalid or malformed lines.\n */\nexport async function loadOutcomeHistory(): Promise<OutcomeEntry[]> {\n let raw: string;\n try {\n raw = await readFile(paths.outcomeHistory, 'utf-8');\n } catch (err: unknown) {\n if (isNodeError(err) && err.code === 'ENOENT') {\n return [];\n }\n throw err;\n }\n\n const entries: OutcomeEntry[] = [];\n const lines = raw.split('\\n').filter((line) => line.trim().length > 0);\n\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line);\n const result = outcomeEntrySchema.safeParse(parsed);\n if (result.success) {\n entries.push(result.data);\n }\n } catch {\n // Skip malformed JSON lines silently\n }\n }\n\n return entries;\n}\n\n/**\n * Compute outcome summaries grouped by pattern_type.\n * For each group: counts unique recommendation_ids, tallies positive\n * (persisted) and negative (reverted) outcomes, and computes\n * persistence_rate = persisted / total_applied.\n *\n * Uses the latest outcome per recommendation_id for determination.\n */\nexport function computeOutcomeSummaries(\n history: OutcomeEntry[],\n): OutcomeSummary[] {\n if (history.length === 0) return [];\n\n // Group by pattern_type\n const groups = new Map<string, OutcomeEntry[]>();\n for (const entry of history) {\n const group = groups.get(entry.pattern_type) ?? [];\n group.push(entry);\n groups.set(entry.pattern_type, group);\n }\n\n const summaries: OutcomeSummary[] = [];\n\n for (const [patternType, entries] of groups) {\n // Get the latest entry per recommendation_id\n const latestByRec = new Map<string, OutcomeEntry>();\n for (const entry of entries) {\n latestByRec.set(entry.recommendation_id, entry);\n }\n\n let totalPersisted = 0;\n let totalReverted = 0;\n\n for (const entry of latestByRec.values()) {\n if (entry.outcome === 'positive') {\n totalPersisted++;\n } else if (entry.outcome === 'negative') {\n totalReverted++;\n }\n // 'monitoring' entries don't count toward either\n }\n\n const totalApplied = latestByRec.size;\n const persistenceRate = totalApplied > 0\n ? totalPersisted / totalApplied\n : 0;\n\n summaries.push({\n pattern_type: patternType,\n total_applied: totalApplied,\n total_persisted: totalPersisted,\n total_reverted: totalReverted,\n persistence_rate: persistenceRate,\n });\n }\n\n return summaries;\n}\n\n/**\n * Infer the pattern type from a recommendation ID prefix.\n * Values must match the exact strings produced by each classifier.\n * For prefixes that map to multiple sub-types (ecosystem, onboarding),\n * the most common sub-type is returned as a best-effort default.\n */\nfunction inferPatternType(id: string): string {\n if (id.startsWith('rec-repeated-')) return 'repeated_prompt';\n if (id.startsWith('rec-long-')) return 'long_prompt';\n if (id.startsWith('rec-permission-always-approved-')) return 'permission-always-approved';\n if (id.startsWith('rec-correction-')) return 'code_correction';\n if (id.startsWith('rec-personal-')) return 'personal_info';\n if (id.startsWith('rec-drift-')) return 'config_drift';\n if (id.startsWith('rec-ecosystem-')) return 'version_update';\n if (id.startsWith('rec-onboarding-')) return 'onboarding_start_hooks';\n if (id.startsWith('rec-tool-preference-')) return 'tool-preference';\n return 'unknown';\n}\n\n/**\n * Infer the routing target from a recommendation ID prefix.\n * Covers all 8 classifier prefixes plus tool-preference.\n */\nfunction inferTarget(id: string): string {\n if (id.startsWith('rec-repeated-')) return 'HOOK';\n if (id.startsWith('rec-long-')) return 'SKILL';\n if (id.startsWith('rec-permission-always-approved-')) return 'SETTINGS';\n if (id.startsWith('rec-correction-')) return 'RULE';\n if (id.startsWith('rec-personal-')) return 'MEMORY';\n if (id.startsWith('rec-drift-')) return 'CLAUDE_MD';\n if (id.startsWith('rec-ecosystem-')) return 'CLAUDE_MD';\n if (id.startsWith('rec-tool-preference-')) return 'SETTINGS';\n if (id.startsWith('rec-onboarding-')) return 'HOOK';\n return 'MEMORY';\n}\n\n// Type guard for Node.js errors with code property\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && 'code' in err;\n}\n","// Recommendation state lifecycle management.\n// Tracks recommendation statuses (pending/applied/dismissed) in a JSON file\n// that survives across analysis re-runs and sessions.\n\nimport { readFile } from 'node:fs/promises';\nimport writeFileAtomic from 'write-file-atomic';\nimport { paths } from '../storage/dirs.js';\nimport {\n recommendationStateSchema,\n type RecommendationState,\n type RecommendationStatus,\n} from '../schemas/delivery.js';\n\n/**\n * Load the recommendation state from disk.\n * Returns an empty state when the file does not exist.\n */\nexport async function loadState(): Promise<RecommendationState> {\n try {\n const raw = await readFile(paths.recommendationState, 'utf-8');\n return recommendationStateSchema.parse(JSON.parse(raw));\n } catch (err: unknown) {\n // File not found or invalid JSON: return empty state\n if (isNodeError(err) && err.code === 'ENOENT') {\n return { entries: [], last_updated: new Date().toISOString() };\n }\n // Re-throw unexpected errors\n throw err;\n }\n}\n\n/**\n * Save the recommendation state atomically to disk.\n */\nexport async function saveState(state: RecommendationState): Promise<void> {\n await writeFileAtomic(\n paths.recommendationState,\n JSON.stringify(state, null, 2),\n );\n}\n\n/**\n * Update the status of a recommendation by ID.\n * Creates a new entry if the ID is not found.\n */\nexport async function updateStatus(\n id: string,\n status: RecommendationStatus,\n details?: string,\n): Promise<void> {\n const state = await loadState();\n const now = new Date().toISOString();\n\n const existing = state.entries.find((e) => e.id === id);\n if (existing) {\n existing.status = status;\n existing.updated_at = now;\n if (status === 'applied' && details !== undefined) {\n existing.applied_details = details;\n } else if (status !== 'applied') {\n // Clear applied_details when not in applied status\n existing.applied_details = undefined;\n }\n } else {\n state.entries.push({\n id,\n status,\n updated_at: now,\n ...(status === 'applied' && details !== undefined\n ? { applied_details: details }\n : {}),\n });\n }\n\n state.last_updated = now;\n await saveState(state);\n}\n\n/**\n * Get a Map of recommendation ID to status for quick lookups.\n */\nexport async function getStatusMap(): Promise<Map<string, RecommendationStatus>> {\n const state = await loadState();\n return new Map(state.entries.map((e) => [e.id, e.status]));\n}\n\n// Type guard for Node.js errors with code property\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && 'code' in err;\n}\n","// Delivery schemas for recommendation state tracking and auto-apply logging.\n// Defines: recommendation status lifecycle (pending/applied/dismissed),\n// state entries persisted in JSON, and auto-apply audit log entries.\n\nimport { z } from 'zod/v4';\n\nexport const recommendationStatusSchema = z.enum(['pending', 'applied', 'dismissed']);\nexport type RecommendationStatus = z.infer<typeof recommendationStatusSchema>;\n\nexport const recommendationStateEntrySchema = z.object({\n id: z.string(),\n status: recommendationStatusSchema,\n updated_at: z.iso.datetime(),\n applied_details: z.string().optional(),\n});\nexport type RecommendationStateEntry = z.infer<typeof recommendationStateEntrySchema>;\n\nexport const recommendationStateSchema = z.object({\n entries: z.array(recommendationStateEntrySchema),\n last_updated: z.iso.datetime(),\n});\nexport type RecommendationState = z.infer<typeof recommendationStateSchema>;\n\nexport const autoApplyLogEntrySchema = z.object({\n timestamp: z.iso.datetime(),\n recommendation_id: z.string(),\n target: z.string(),\n action: z.string(),\n success: z.boolean(),\n details: z.string().optional(),\n backup_path: z.string().optional(),\n});\nexport type AutoApplyLogEntry = z.infer<typeof autoApplyLogEntrySchema>;\n","// Phase 6 schemas for onboarding detection and outcome tracking.\n// Defines: experience tier classification, experience level with score\n// breakdown, outcome tracking entries, and outcome summary aggregation.\n\nimport { z } from 'zod/v4';\n\n// Experience level types\nexport const experienceTierSchema = z.enum(['newcomer', 'intermediate', 'power_user']);\nexport type ExperienceTier = z.infer<typeof experienceTierSchema>;\n\nexport const experienceLevelSchema = z.object({\n tier: experienceTierSchema,\n score: z.number().min(0).max(100),\n breakdown: z.object({\n hooks: z.number(),\n rules: z.number(),\n skills: z.number(),\n plugins: z.number(),\n claude_md: z.number(),\n ecosystems: z.number(),\n }),\n});\nexport type ExperienceLevel = z.infer<typeof experienceLevelSchema>;\n\n// Outcome tracking types (used by Plan 02)\nexport const outcomeEntrySchema = z.object({\n recommendation_id: z.string(),\n pattern_type: z.string(),\n target: z.string(),\n applied_at: z.iso.datetime(),\n checked_at: z.iso.datetime(),\n persisted: z.boolean(),\n checks_since_applied: z.number(),\n outcome: z.enum(['positive', 'negative', 'monitoring']),\n});\nexport type OutcomeEntry = z.infer<typeof outcomeEntrySchema>;\n\nexport const outcomeSummarySchema = z.object({\n pattern_type: z.string(),\n total_applied: z.number(),\n total_persisted: z.number(),\n total_reverted: z.number(),\n persistence_rate: z.number(),\n});\nexport type OutcomeSummary = z.infer<typeof outcomeSummarySchema>;\n","// Threshold trigger: orchestrates analysis when counter reaches the configured\n// threshold. Respects cooldown period, resets counter after success, preserves\n// counter on failure for automatic retry at next threshold check.\n\nimport { readCounter } from '../storage/counter.js';\nimport { loadConfig } from '../storage/config.js';\nimport { paths, ensureInit } from '../storage/dirs.js';\nimport { preProcess } from './pre-processor.js';\nimport { scanEnvironment } from './environment-scanner.js';\nimport { analyze } from './analyzer.js';\nimport {\n trackOutcomes,\n loadOutcomeHistory,\n computeOutcomeSummaries,\n} from './outcome-tracker.js';\nimport type { OutcomeSummary } from '../schemas/onboarding.js';\nimport type { AnalysisResult } from '../schemas/recommendation.js';\nimport writeFileAtomic from 'write-file-atomic';\nimport { readFile } from 'node:fs/promises';\nimport { lock } from 'proper-lockfile';\n\n// Cooldown period: prevent re-triggering analysis within 60 seconds of last run\nconst COOLDOWN_MS = 60_000;\n\n/**\n * Write an AnalysisResult to the analysis-result.json path atomically.\n */\nexport async function writeAnalysisResult(\n result: AnalysisResult,\n): Promise<void> {\n await ensureInit();\n await writeFileAtomic(paths.analysisResult, JSON.stringify(result, null, 2));\n}\n\n/**\n * Run the full analysis pipeline: preProcess -> scanEnvironment -> analyze -> write.\n *\n * @param cwd - Current working directory for environment scanning\n * @returns The generated AnalysisResult\n */\nexport async function runAnalysis(cwd: string): Promise<AnalysisResult> {\n const summary = await preProcess();\n const snapshot = await scanEnvironment(cwd);\n\n // Wire outcome tracking: track current state, compute summaries for confidence adjustment (QUA-04)\n let outcomeSummaries: OutcomeSummary[] | undefined;\n try {\n await trackOutcomes(snapshot);\n const history = await loadOutcomeHistory();\n outcomeSummaries = computeOutcomeSummaries(history);\n } catch {\n // Outcome tracking failure must not block analysis\n }\n\n const result = analyze(summary, snapshot, undefined, outcomeSummaries);\n await writeAnalysisResult(result);\n return result;\n}\n\n/**\n * Reset the counter with a last_analysis timestamp atomically.\n * Uses proper-lockfile for cross-process safety.\n */\nasync function resetCounterWithTimestamp(): Promise<void> {\n // Ensure counter file exists before locking\n try {\n await readFile(paths.counter, 'utf-8');\n } catch {\n const initial = {\n total: 0,\n session: {},\n last_updated: new Date().toISOString(),\n };\n await writeFileAtomic(paths.counter, JSON.stringify(initial, null, 2));\n }\n\n const release = await lock(paths.counter, {\n retries: { retries: 50, minTimeout: 20, maxTimeout: 1000, randomize: true },\n stale: 10000,\n });\n\n try {\n const now = new Date().toISOString();\n const data = {\n total: 0,\n session: {},\n last_analysis: now,\n last_updated: now,\n };\n await writeFileAtomic(paths.counter, JSON.stringify(data, null, 2));\n } finally {\n await release();\n }\n}\n\n/**\n * Check if analysis should be triggered and run it if conditions are met.\n *\n * Conditions:\n * 1. analysis.enabled is true in config\n * 2. counter.total >= config.analysis.threshold\n * 3. Not within cooldown period since last_analysis\n *\n * On success: resets counter and records last_analysis timestamp.\n * On failure: preserves counter data for retry at next check.\n *\n * @param cwd - Current working directory\n * @returns true if analysis was triggered, false otherwise\n */\nexport async function checkAndTriggerAnalysis(\n cwd: string,\n): Promise<boolean> {\n const config = await loadConfig();\n if (!config.analysis.enabled) return false;\n\n const counter = await readCounter();\n if (counter.total < config.analysis.threshold) return false;\n\n // Check cooldown\n if (counter.last_analysis) {\n const elapsed = Date.now() - new Date(counter.last_analysis).getTime();\n if (elapsed < COOLDOWN_MS) return false;\n }\n\n // Attempt analysis -- preserve counter on failure\n try {\n await runAnalysis(cwd);\n } catch {\n return false;\n }\n\n // Reset counter with timestamp after successful analysis\n await resetCounterWithTimestamp();\n return true;\n}\n","// Markdown renderer for analysis results.\n// Produces structured recommendations grouped by confidence tier\n// with status prefixes, evidence, and suggested actions.\n\nimport type { AnalysisResult } from '../schemas/recommendation.js';\nimport type { RecommendationStatus } from '../schemas/delivery.js';\n\nconst TIER_ORDER: readonly string[] = ['HIGH', 'MEDIUM', 'LOW'] as const;\n\n/**\n * Render an AnalysisResult to a markdown string grouped by confidence tier.\n * Status prefixes (PENDING/APPLIED/DISMISSED) are looked up from the states map.\n */\nexport function renderRecommendations(\n result: AnalysisResult,\n states: Map<string, RecommendationStatus>,\n): string {\n const lines: string[] = [];\n\n // Header\n lines.push('# harness-evolve Recommendations');\n lines.push('');\n lines.push(`*Generated: ${result.generated_at}*`);\n lines.push(\n `*Period: ${result.summary_period.since} to ${result.summary_period.until} (${result.summary_period.days} days)*`,\n );\n lines.push('');\n\n // Empty case\n if (result.recommendations.length === 0) {\n lines.push('No recommendations at this time.');\n lines.push('');\n lines.push('---');\n lines.push('*Run /evolve to refresh or manage recommendations.*');\n return lines.join('\\n');\n }\n\n // Group by confidence tier\n for (const tier of TIER_ORDER) {\n const tierRecs = result.recommendations.filter(\n (r) => r.confidence === tier,\n );\n if (tierRecs.length === 0) continue;\n\n lines.push(`## ${tier} Confidence`);\n lines.push('');\n\n for (const rec of tierRecs) {\n const status = (states.get(rec.id) ?? 'pending').toUpperCase();\n\n lines.push(`### [${status}] ${rec.title}`);\n lines.push('');\n lines.push(`**Target:** ${rec.target} | **Pattern:** ${rec.pattern_type}`);\n\n // Evidence line\n const evidenceParts = [`${rec.evidence.count} occurrences`];\n if (rec.evidence.sessions !== undefined) {\n evidenceParts.push(`across ${rec.evidence.sessions} sessions`);\n }\n lines.push(`**Evidence:** ${evidenceParts.join(' ')}`);\n lines.push('');\n\n // Description\n lines.push(rec.description);\n lines.push('');\n\n // Evidence examples\n if (rec.evidence.examples.length > 0) {\n lines.push('**Examples:**');\n for (const ex of rec.evidence.examples) {\n lines.push(`- \\`${ex}\\``);\n }\n lines.push('');\n }\n\n // Suggested action\n lines.push(`**Suggested action:** ${rec.suggested_action}`);\n lines.push('');\n\n // Ecosystem context (optional)\n if (rec.ecosystem_context !== undefined) {\n lines.push(`**Ecosystem note:** ${rec.ecosystem_context}`);\n lines.push('');\n }\n }\n }\n\n // Footer\n lines.push('---');\n lines.push('*Run /evolve to refresh or manage recommendations.*');\n\n return lines.join('\\n');\n}\n","// Recommendation rotator for bounding the state file size.\n// Archives applied/dismissed entries older than archiveAfterDays\n// to dated JSON files in the archive directory.\n\nimport { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport writeFileAtomic from 'write-file-atomic';\nimport { paths } from '../storage/dirs.js';\nimport { loadState, saveState } from './state.js';\n\ninterface RotatorConfig {\n maxRecommendationsInFile: number;\n archiveAfterDays: number;\n}\n\n/**\n * Rotate old applied/dismissed recommendations to archive files.\n * Pending entries are never archived regardless of age.\n */\nexport async function rotateRecommendations(\n config: RotatorConfig,\n): Promise<void> {\n const state = await loadState();\n const cutoff = new Date(Date.now() - config.archiveAfterDays * 86400_000);\n\n const toArchive = state.entries.filter(\n (e) =>\n (e.status === 'applied' || e.status === 'dismissed') &&\n new Date(e.updated_at) < cutoff,\n );\n\n if (toArchive.length === 0) {\n return;\n }\n\n const toKeep = state.entries.filter(\n (e) => !toArchive.some((a) => a.id === e.id),\n );\n\n // Write archive file with today's date\n const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD\n const archivePath = join(paths.recommendationArchive, `${today}.json`);\n await mkdir(paths.recommendationArchive, { recursive: true });\n await writeFileAtomic(archivePath, JSON.stringify(toArchive, null, 2));\n\n // Update state with only kept entries\n await saveState({\n entries: toKeep,\n last_updated: new Date().toISOString(),\n });\n}\n","// Notification module for harness-evolve delivery.\n// Builds one-line notification messages and manages the notification flag file\n// that signals pending recommendations to the UserPromptSubmit hook.\n\nimport { existsSync } from 'node:fs';\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { paths } from '../storage/dirs.js';\n\n/**\n * Build a one-line notification string referencing /evolve:apply.\n * Output is always under 200 characters (well under 200 tokens).\n */\nexport function buildNotification(pendingCount: number): string {\n const plural = pendingCount === 1 ? '' : 's';\n return `[harness-evolve] ${pendingCount} new suggestion${plural} found. Run /evolve:apply to review.`;\n}\n\n/**\n * Write the notification flag file with the pending recommendation count.\n * The UserPromptSubmit hook reads this flag to decide whether to inject a notification.\n */\nexport async function writeNotificationFlag(pendingCount: number): Promise<void> {\n await writeFile(paths.notificationFlag, String(pendingCount), 'utf-8');\n}\n\n/**\n * Check whether a notification flag file exists.\n */\nexport async function hasNotificationFlag(): Promise<boolean> {\n return existsSync(paths.notificationFlag);\n}\n\n/**\n * Remove the notification flag file.\n * Does not throw when the flag file does not exist.\n */\nexport async function clearNotificationFlag(): Promise<void> {\n try {\n await unlink(paths.notificationFlag);\n } catch {\n // Flag already cleared or never existed\n }\n}\n\n/**\n * Read the pending count from the notification flag file.\n * Returns 0 if the file cannot be read or parsed.\n */\nexport async function readNotificationFlagCount(): Promise<number> {\n try {\n const content = await readFile(paths.notificationFlag, 'utf-8');\n return parseInt(content.trim(), 10) || 0;\n } catch {\n return 0;\n }\n}\n","// Auto-apply module for high-confidence recommendations.\n// When fullAuto mode is enabled (config.delivery.fullAuto=true), this module\n// automatically applies HIGH-confidence recommendations that have a registered\n// applier. Dispatches to the correct applier via the strategy pattern registry.\n// v1 appliers: SettingsApplier (permission-always-approved), RuleApplier (create-only rules).\n// v2 appliers: HookApplier (hook script generation + settings registration), ClaudeMdApplier (CLAUDE.md append).\n\nimport { appendFile } from 'node:fs/promises';\nimport { paths, ensureInit } from '../storage/dirs.js';\nimport { loadConfig } from '../storage/config.js';\nimport { updateStatus, getStatusMap } from './state.js';\nimport {\n registerApplier,\n getApplier,\n hasApplier,\n} from './appliers/index.js';\nimport { SettingsApplier } from './appliers/settings-applier.js';\nimport { RuleApplier } from './appliers/rule-applier.js';\nimport { HookApplier } from './appliers/hook-applier.js';\nimport { ClaudeMdApplier } from './appliers/claude-md-applier.js';\nimport type { Recommendation } from '../schemas/recommendation.js';\nimport type { AutoApplyLogEntry } from '../schemas/delivery.js';\nimport type { ApplierOptions } from './appliers/index.js';\n\nexport interface AutoApplyResult {\n recommendation_id: string;\n success: boolean;\n details: string;\n}\n\nexport interface AutoApplyOptions extends ApplierOptions {}\n\n// Register all built-in appliers\nregisterApplier(new SettingsApplier());\nregisterApplier(new RuleApplier());\nregisterApplier(new HookApplier());\nregisterApplier(new ClaudeMdApplier());\n\n/**\n * Auto-apply HIGH-confidence recommendations when fullAuto is enabled.\n * Returns an empty array when fullAuto is false (default, per QUA-01).\n *\n * Dispatches to the appropriate Applier based on rec.target via the\n * applier registry. Only processes recommendations whose target has a\n * registered applier and whose applier.canApply() returns true.\n */\nexport async function autoApplyRecommendations(\n recommendations: Recommendation[],\n options?: AutoApplyOptions,\n): Promise<AutoApplyResult[]> {\n const config = await loadConfig();\n if (!config.delivery.fullAuto) return [];\n\n await ensureInit();\n const stateMap = await getStatusMap();\n const results: AutoApplyResult[] = [];\n\n // Filter: only HIGH confidence + has registered applier + pending status\n const candidates = recommendations.filter(\n (rec) =>\n rec.confidence === 'HIGH' &&\n hasApplier(rec.target) &&\n (stateMap.get(rec.id) ?? 'pending') === 'pending',\n );\n\n for (const rec of candidates) {\n const applier = getApplier(rec.target);\n let result: AutoApplyResult;\n\n if (!applier || !applier.canApply(rec)) {\n result = {\n recommendation_id: rec.id,\n success: false,\n details: `No applicable applier for target '${rec.target}' with pattern_type '${rec.pattern_type}'`,\n };\n } else {\n result = await applier.apply(rec, options);\n }\n\n results.push(result);\n\n // Log the attempt\n const logEntry: AutoApplyLogEntry = {\n timestamp: new Date().toISOString(),\n recommendation_id: rec.id,\n target: rec.target,\n action: rec.suggested_action,\n success: result.success,\n details: result.details,\n backup_path: undefined,\n };\n await appendFile(\n paths.autoApplyLog,\n JSON.stringify(logEntry) + '\\n',\n 'utf-8',\n );\n\n // Update status on success\n if (result.success) {\n await updateStatus(rec.id, 'applied', `Auto-applied: ${result.details}`);\n }\n }\n\n return results;\n}\n","// Applier interface, options, and registry for auto-apply dispatch.\n// The registry maps routing targets (e.g. 'SETTINGS', 'RULE') to their\n// corresponding Applier implementations. Adding a new applier requires\n// only implementing the Applier interface and calling registerApplier().\n\nimport type { Recommendation } from '../../schemas/recommendation.js';\nimport type { AutoApplyResult } from '../auto-apply.js';\n\nexport interface ApplierOptions {\n /** Override settings.json path (used in testing) */\n settingsPath?: string;\n /** Override rules directory (used in testing) */\n rulesDir?: string;\n /** Override hooks directory (used in testing) */\n hooksDir?: string;\n /** Override CLAUDE.md path (used in testing) */\n claudeMdPath?: string;\n}\n\nexport interface Applier {\n readonly target: string;\n canApply(rec: Recommendation): boolean;\n apply(rec: Recommendation, options?: ApplierOptions): Promise<AutoApplyResult>;\n}\n\nconst registry = new Map<string, Applier>();\n\nexport function registerApplier(applier: Applier): void {\n registry.set(applier.target, applier);\n}\n\nexport function getApplier(target: string): Applier | undefined {\n return registry.get(target);\n}\n\nexport function hasApplier(target: string): boolean {\n return registry.has(target);\n}\n","// SettingsApplier: handles auto-apply for SETTINGS/permission-always-approved.\n// Extracted from auto-apply.ts — adds tools to allowedTools in settings.json\n// with atomic writes and backup creation before modification.\n\nimport { readFile, copyFile, mkdir } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport writeFileAtomic from 'write-file-atomic';\nimport type { Applier, ApplierOptions } from './index.js';\nimport type { Recommendation } from '../../schemas/recommendation.js';\nimport type { AutoApplyResult } from '../auto-apply.js';\nimport { paths } from '../../storage/dirs.js';\n\nexport class SettingsApplier implements Applier {\n readonly target = 'SETTINGS';\n\n canApply(rec: Recommendation): boolean {\n return (\n rec.confidence === 'HIGH' &&\n rec.target === 'SETTINGS' &&\n rec.pattern_type === 'permission-always-approved'\n );\n }\n\n async apply(\n rec: Recommendation,\n options?: ApplierOptions,\n ): Promise<AutoApplyResult> {\n try {\n // v1 scope: only handle permission-always-approved pattern\n if (rec.pattern_type !== 'permission-always-approved') {\n return {\n recommendation_id: rec.id,\n success: false,\n details: `Skipped: pattern_type '${rec.pattern_type}' not supported for auto-apply in v1`,\n };\n }\n\n const settingsFilePath =\n options?.settingsPath ??\n join(process.env.HOME ?? '', '.claude', 'settings.json');\n\n // Read current settings\n const raw = await readFile(settingsFilePath, 'utf-8');\n const settings = JSON.parse(raw) as Record<string, unknown>;\n\n // Create backup before modification\n const backup = join(\n paths.analysis,\n 'backups',\n `settings-backup-${rec.id}.json`,\n );\n await mkdir(dirname(backup), { recursive: true });\n await copyFile(settingsFilePath, backup);\n\n // Extract tool name from evidence\n const toolName = extractToolName(rec);\n if (!toolName) {\n return {\n recommendation_id: rec.id,\n success: false,\n details:\n 'Could not extract tool name from recommendation evidence',\n };\n }\n\n // Get or create allowedTools array\n const allowedTools = Array.isArray(settings.allowedTools)\n ? (settings.allowedTools as string[])\n : [];\n\n // Add tool if not already present\n if (!allowedTools.includes(toolName)) {\n allowedTools.push(toolName);\n }\n settings.allowedTools = allowedTools;\n\n // Write modified settings atomically\n await writeFileAtomic(\n settingsFilePath,\n JSON.stringify(settings, null, 2),\n );\n\n return {\n recommendation_id: rec.id,\n success: true,\n details: `Added ${toolName} to allowedTools`,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n recommendation_id: rec.id,\n success: false,\n details: message,\n };\n }\n }\n}\n\n/**\n * Extract tool name from recommendation evidence examples.\n * Looks for patterns like \"Bash(npm test)\" -> \"Bash\"\n * or \"ToolName(args)\" -> \"ToolName\".\n */\nfunction extractToolName(rec: Recommendation): string | undefined {\n for (const example of rec.evidence.examples) {\n const match = example.match(/^(\\w+)\\(/);\n if (match) return match[1];\n }\n return undefined;\n}\n","// RuleApplier: handles auto-apply for HIGH-confidence RULE recommendations.\n// Creates .claude/rules/evolve-{pattern_type}.md files with the recommendation\n// title, description, and suggested action. Create-only: never overwrites\n// existing rule files to respect user customizations (Pitfall 18).\n\nimport { writeFile, access, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Applier, ApplierOptions } from './index.js';\nimport type { Recommendation } from '../../schemas/recommendation.js';\nimport type { AutoApplyResult } from '../auto-apply.js';\n\nexport class RuleApplier implements Applier {\n readonly target = 'RULE';\n\n canApply(rec: Recommendation): boolean {\n return rec.confidence === 'HIGH' && rec.target === 'RULE';\n }\n\n async apply(\n rec: Recommendation,\n options?: ApplierOptions,\n ): Promise<AutoApplyResult> {\n const rulesDir =\n options?.rulesDir ??\n join(process.env.HOME ?? '', '.claude', 'rules');\n const fileName = `evolve-${rec.pattern_type}.md`;\n const filePath = join(rulesDir, fileName);\n\n // Create-only guard: never overwrite existing files (Pitfall 18)\n try {\n await access(filePath);\n return {\n recommendation_id: rec.id,\n success: false,\n details: `Rule file already exists: ${fileName}`,\n };\n } catch {\n // File does not exist — proceed to create\n }\n\n try {\n await mkdir(rulesDir, { recursive: true });\n\n const content = [\n `# ${rec.title}`,\n '',\n rec.description,\n '',\n '## Action',\n '',\n rec.suggested_action,\n '',\n '---',\n `*Auto-generated by harness-evolve (${rec.id})*`,\n ].join('\\n');\n\n await writeFile(filePath, content, 'utf-8');\n\n return {\n recommendation_id: rec.id,\n success: true,\n details: `Created rule file: ${fileName}`,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n recommendation_id: rec.id,\n success: false,\n details: message,\n };\n }\n }\n}\n","// HookApplier: handles auto-apply for HIGH-confidence HOOK recommendations.\n// Generates a bash hook script via generateHook(), writes it to disk with +x\n// permission, and registers the hook in settings.json via mergeHooks().\n// Create-only: never overwrites existing hook files.\n\nimport { writeFile, access, mkdir, chmod, copyFile } from 'node:fs/promises';\nimport { join, basename, dirname } from 'node:path';\nimport type { Applier, ApplierOptions } from './index.js';\nimport type { Recommendation } from '../../schemas/recommendation.js';\nimport type { AutoApplyResult } from '../auto-apply.js';\nimport { generateHook } from '../../generators/hook-generator.js';\nimport {\n readSettings,\n writeSettings,\n mergeHooks,\n} from '../../cli/utils.js';\nimport { paths } from '../../storage/dirs.js';\n\nexport class HookApplier implements Applier {\n readonly target = 'HOOK';\n\n canApply(rec: Recommendation): boolean {\n return rec.confidence === 'HIGH' && rec.target === 'HOOK';\n }\n\n async apply(\n rec: Recommendation,\n options?: ApplierOptions,\n ): Promise<AutoApplyResult> {\n try {\n // Generate hook script from recommendation\n const artifact = generateHook(rec);\n if (!artifact) {\n return {\n recommendation_id: rec.id,\n success: false,\n details: 'Generator returned null — recommendation not applicable for hook generation',\n };\n }\n\n // Resolve hooks directory\n const hooksDir =\n options?.hooksDir ??\n join(process.env.HOME ?? '', '.claude', 'hooks');\n\n // Extract script filename from artifact path\n const scriptFilename = basename(artifact.filename);\n const scriptPath = join(hooksDir, scriptFilename);\n\n // Create-only guard: never overwrite existing hook files\n try {\n await access(scriptPath);\n return {\n recommendation_id: rec.id,\n success: false,\n details: `Hook file already exists: ${scriptFilename}`,\n };\n } catch {\n // File does not exist — proceed to create\n }\n\n // Create hooks directory\n await mkdir(hooksDir, { recursive: true });\n\n // Write hook script file\n await writeFile(scriptPath, artifact.content, 'utf-8');\n\n // Set executable permission\n await chmod(scriptPath, 0o755);\n\n // Resolve settings.json path\n const settingsPath =\n options?.settingsPath ??\n join(process.env.HOME ?? '', '.claude', 'settings.json');\n\n // Read current settings\n const settings = await readSettings(settingsPath);\n\n // Create backup before modification\n const backupDir = join(paths.analysis, 'backups');\n await mkdir(backupDir, { recursive: true });\n const backupFile = join(backupDir, `settings-backup-${rec.id}.json`);\n // Only backup if settings file exists and has content\n try {\n await copyFile(settingsPath, backupFile);\n } catch {\n // Settings file may not exist yet — write current state as backup\n await writeFile(backupFile, JSON.stringify(settings, null, 2), 'utf-8');\n }\n\n // Extract hook event from generated content\n const eventMatch = artifact.content.match(/# Hook event: (\\w+)/);\n const hookEvent = eventMatch?.[1] ?? 'PreToolUse';\n\n // Merge hook into settings\n const merged = mergeHooks(settings, [\n {\n event: hookEvent,\n command: `bash \"${scriptPath}\"`,\n timeout: 10,\n async: true,\n },\n ]);\n\n // Write merged settings\n await writeSettings(merged, settingsPath);\n\n return {\n recommendation_id: rec.id,\n success: true,\n details: `Created hook script: ${scriptFilename} and registered under ${hookEvent}`,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n recommendation_id: rec.id,\n success: false,\n details: message,\n };\n }\n }\n}\n","// Generator module schemas and shared utilities.\n// Defines the GeneratedArtifact output contract for all generators,\n// plus helper functions (toSlug, escapeYaml) used across generator implementations.\n\nimport { z } from 'zod/v4';\n\n// Version stamp embedded in every generated artifact\nexport const GENERATOR_VERSION = '1.0.0';\n\n// Return current time as ISO 8601 string\nexport function nowISO(): string {\n return new Date().toISOString();\n}\n\n/**\n * Convert text to a URL/filename-safe slug.\n * Lowercases, replaces non-alphanumeric with hyphens,\n * collapses consecutive hyphens, strips leading/trailing hyphens,\n * and caps at 50 characters.\n */\nexport function toSlug(text: string): string {\n if (!text) return '';\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 50);\n}\n\n// Characters that require quoting in YAML values\nconst YAML_SPECIAL = /[:\"'{}[\\]#&*!|>\\\\,\\n]/;\n\n/**\n * Escape a string for safe inclusion as a YAML frontmatter value.\n * Wraps in double quotes and escapes internal double quotes\n * when the text contains YAML-special characters.\n */\nexport function escapeYaml(text: string): string {\n if (!YAML_SPECIAL.test(text)) return text;\n return `\"${text.replace(/\"/g, '\\\\\"')}\"`;\n}\n\nexport const generatedArtifactSchema = z.object({\n type: z.enum(['skill', 'hook', 'claude_md_patch']),\n filename: z.string(),\n content: z.string(),\n source_recommendation_id: z.string(),\n metadata: z.object({\n generated_at: z.iso.datetime(),\n generator_version: z.string(),\n pattern_type: z.string(),\n }),\n});\nexport type GeneratedArtifact = z.infer<typeof generatedArtifactSchema>;\n\nexport interface GeneratorOptions {\n projectRoot?: string;\n}\n","// Hook generator: converts HOOK-targeted recommendations into bash hook\n// script drafts. Handles both scan_missing_mechanization and repeated_prompt\n// pattern types. Pure function -- no filesystem access, no side effects.\n// Returns null for non-applicable recommendations.\n\nimport type { Recommendation } from '../schemas/recommendation.js';\nimport type { GeneratedArtifact } from './schemas.js';\nimport { toSlug, GENERATOR_VERSION, nowISO } from './schemas.js';\n\n/**\n * Extract the hook event name from a recommendation's description\n * or suggested_action field.\n *\n * Tries these patterns in order:\n * 1. \"suitable for a <HookEvent> hook\" in description\n * 2. \"Create a <HookEvent> hook\" in suggested_action\n * 3. Falls back to 'PreToolUse' if no match\n */\nfunction extractHookEvent(rec: Recommendation): string {\n const descMatch = rec.description.match(/suitable for a (\\w+) hook/i);\n if (descMatch) return descMatch[1];\n\n const actionMatch = rec.suggested_action.match(/Create a (\\w+) hook/i);\n if (actionMatch) return actionMatch[1];\n\n return 'PreToolUse';\n}\n\n/**\n * Generate a bash hook script draft from a HOOK-targeted recommendation.\n *\n * @param rec - A Recommendation object (from mechanization scanner or repeated-prompts classifier)\n * @returns GeneratedArtifact with type 'hook', or null if the recommendation\n * is not applicable (wrong target)\n */\nexport function generateHook(rec: Recommendation): GeneratedArtifact | null {\n if (rec.target !== 'HOOK') return null;\n\n const hookEvent = extractHookEvent(rec);\n const slugName = toSlug(rec.title);\n\n const content = [\n '#!/usr/bin/env bash',\n `# Auto-generated hook for: ${rec.title}`,\n `# Hook event: ${hookEvent}`,\n `# Source: harness-evolve (${rec.id})`,\n '#',\n '# TODO: Review and customize this script before use.',\n '',\n '# Read hook input from stdin',\n 'INPUT=$(cat)',\n '',\n '# Extract relevant fields',\n `# Adjust jq path based on your ${hookEvent} event schema`,\n '',\n `# ${rec.suggested_action}`,\n '',\n '# Exit 0 to allow, exit 2 to block',\n 'exit 0',\n ].join('\\n');\n\n return {\n type: 'hook',\n filename: `.claude/hooks/evolve-${slugName}.sh`,\n content,\n source_recommendation_id: rec.id,\n metadata: {\n generated_at: nowISO(),\n generator_version: GENERATOR_VERSION,\n pattern_type: rec.pattern_type,\n },\n };\n}\n","// Shared CLI utilities: hook definitions, settings I/O, path resolution, confirm prompt\n\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport writeFileAtomic from 'write-file-atomic';\n\n/**\n * Marker string used to identify harness-evolve hook entries in settings.json.\n * When scanning existing hooks, any command containing this string is ours.\n */\nexport const HARNESS_EVOLVE_MARKER = 'harness-evolve';\n\n/**\n * Default path to Claude Code user-scope settings.json.\n */\nexport const SETTINGS_PATH = join(\n process.env.HOME ?? '',\n '.claude',\n 'settings.json',\n);\n\n/**\n * Hook registration definition.\n */\nexport interface HookRegistration {\n event: string;\n hookFile: string;\n timeout: number;\n async: boolean;\n description: string;\n}\n\n/**\n * All 6 hook events that harness-evolve registers.\n * Each entry maps an event name to the compiled JS hook file.\n */\nexport const HOOK_REGISTRATIONS: HookRegistration[] = [\n {\n event: 'UserPromptSubmit',\n hookFile: 'user-prompt-submit.js',\n timeout: 10,\n async: false,\n description: 'Captures prompts and delivers optimization notifications',\n },\n {\n event: 'PreToolUse',\n hookFile: 'pre-tool-use.js',\n timeout: 10,\n async: true,\n description: 'Tracks tool usage patterns before execution',\n },\n {\n event: 'PostToolUse',\n hookFile: 'post-tool-use.js',\n timeout: 10,\n async: true,\n description: 'Records tool outcomes for pattern analysis',\n },\n {\n event: 'PostToolUseFailure',\n hookFile: 'post-tool-use-failure.js',\n timeout: 10,\n async: true,\n description: 'Logs tool failures to detect correction patterns',\n },\n {\n event: 'PermissionRequest',\n hookFile: 'permission-request.js',\n timeout: 10,\n async: true,\n description: 'Monitors permission decisions for auto-approval suggestions',\n },\n {\n event: 'Stop',\n hookFile: 'stop.js',\n timeout: 10,\n async: true,\n description: 'Triggers analysis when interaction threshold is reached',\n },\n];\n\n/**\n * Resolve absolute path to a hook JS file.\n *\n * In production, import.meta.dirname of the compiled dist/cli/utils.js\n * points to <install>/dist/cli/. We go up one level to <install>/dist/,\n * then into hooks/<hookFile>.\n *\n * @param hookFile - The hook filename (e.g., 'user-prompt-submit.js')\n * @param baseDirOverride - Override for import.meta.dirname (for testing)\n */\nexport function resolveHookPath(\n hookFile: string,\n baseDirOverride?: string,\n): string {\n const baseDir = baseDirOverride ?? import.meta.dirname;\n return join(baseDir, 'hooks', hookFile);\n}\n\n/**\n * Read and parse Claude Code settings.json.\n * Returns empty object if file does not exist or JSON is invalid.\n */\nexport async function readSettings(\n settingsPath?: string,\n): Promise<Record<string, unknown>> {\n const filePath = settingsPath ?? SETTINGS_PATH;\n try {\n const raw = await readFile(filePath, 'utf-8');\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // ENOENT (file missing) or SyntaxError (invalid JSON)\n return {};\n }\n}\n\n/**\n * Write settings.json atomically with 2-space indentation.\n */\nexport async function writeSettings(\n settings: Record<string, unknown>,\n settingsPath?: string,\n): Promise<void> {\n const filePath = settingsPath ?? SETTINGS_PATH;\n await writeFileAtomic(filePath, JSON.stringify(settings, null, 2));\n}\n\n/**\n * Hook command entry for merge logic.\n */\ninterface HookCommand {\n event: string;\n command: string;\n timeout: number;\n async: boolean;\n}\n\n/**\n * Merge harness-evolve hooks into existing settings without destroying user hooks.\n *\n * For each hook command:\n * - If the event already has a harness-evolve entry (identified by HARNESS_EVOLVE_MARKER\n * in the command string), skip it.\n * - Otherwise, append a new matcher entry to the event array.\n *\n * User hooks are preserved untouched.\n */\nexport function mergeHooks(\n existing: Record<string, unknown>,\n hookCommands: HookCommand[],\n): Record<string, unknown> {\n const hooks = (\n existing.hooks != null ? { ...(existing.hooks as Record<string, unknown>) } : {}\n ) as Record<string, unknown[]>;\n\n for (const hc of hookCommands) {\n const eventArray = (\n Array.isArray(hooks[hc.event]) ? [...hooks[hc.event]] : []\n ) as Array<Record<string, unknown>>;\n\n // Check if harness-evolve hook already registered for this event\n const alreadyRegistered = eventArray.some((entry) => {\n const innerHooks = entry.hooks as\n | Array<Record<string, unknown>>\n | undefined;\n if (!Array.isArray(innerHooks)) return false;\n return innerHooks.some((h) =>\n String(h.command ?? '').includes(HARNESS_EVOLVE_MARKER),\n );\n });\n\n if (!alreadyRegistered) {\n const hookEntry: Record<string, unknown> = {\n type: 'command',\n command: hc.command,\n timeout: hc.timeout,\n };\n if (hc.async) {\n hookEntry.async = true;\n }\n\n eventArray.push({\n matcher: '*',\n hooks: [hookEntry],\n });\n }\n\n hooks[hc.event] = eventArray;\n }\n\n return { ...existing, hooks };\n}\n\n/**\n * Interactive confirmation prompt.\n * Returns true if user answers 'y' or 'yes' (case-insensitive).\n */\nexport async function confirm(message: string): Promise<boolean> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const answer = await rl.question(`${message} [y/N] `);\n return /^y(es)?$/i.test(answer.trim());\n } finally {\n rl.close();\n }\n}\n","// ClaudeMdApplier: handles auto-apply for HIGH-confidence CLAUDE_MD recommendations.\n// Appends new sections to CLAUDE.md for generic pattern types. Refuses to\n// auto-apply destructive patterns (scan_stale_reference, scan_redundancy) that\n// require manual review. Uses write-file-atomic for safe writes.\n// Creates backup of original CLAUDE.md before modification.\n\nimport { readFile, mkdir } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport writeFileAtomic from 'write-file-atomic';\nimport type { Applier, ApplierOptions } from './index.js';\nimport type { Recommendation } from '../../schemas/recommendation.js';\nimport type { AutoApplyResult } from '../auto-apply.js';\nimport { paths } from '../../storage/dirs.js';\n\n/** Pattern types that require manual review — no destructive auto-apply. */\nconst DESTRUCTIVE_PATTERNS = new Set([\n 'scan_stale_reference',\n 'scan_redundancy',\n]);\n\nexport class ClaudeMdApplier implements Applier {\n readonly target = 'CLAUDE_MD';\n\n canApply(rec: Recommendation): boolean {\n return rec.confidence === 'HIGH' && rec.target === 'CLAUDE_MD';\n }\n\n async apply(\n rec: Recommendation,\n options?: ApplierOptions,\n ): Promise<AutoApplyResult> {\n try {\n // Pattern-type guard: refuse destructive patterns\n if (DESTRUCTIVE_PATTERNS.has(rec.pattern_type)) {\n return {\n recommendation_id: rec.id,\n success: false,\n details: `Pattern type '${rec.pattern_type}' requires manual review — cannot safely auto-apply`,\n };\n }\n\n // Resolve CLAUDE.md path\n const claudeMdPath =\n options?.claudeMdPath ??\n join(process.cwd(), 'CLAUDE.md');\n\n // Read existing content (empty string if file doesn't exist)\n let existingContent = '';\n try {\n existingContent = await readFile(claudeMdPath, 'utf-8');\n } catch {\n // File does not exist — will be created\n }\n\n // Create backup if content exists\n if (existingContent) {\n const backupDir = join(paths.analysis, 'backups');\n await mkdir(backupDir, { recursive: true });\n const backupFile = join(backupDir, `claudemd-backup-${rec.id}.md`);\n await writeFileAtomic(backupFile, existingContent);\n }\n\n // Build new section to append\n const newSection = [\n '',\n '',\n `## ${rec.title}`,\n '',\n rec.suggested_action,\n '',\n '---',\n `*Auto-generated by harness-evolve (${rec.id})*`,\n '',\n ].join('\\n');\n\n // Append section to existing content\n const updatedContent = existingContent + newSection;\n\n // Ensure parent directory exists\n await mkdir(dirname(claudeMdPath), { recursive: true });\n\n // Write updated content atomically\n await writeFileAtomic(claudeMdPath, updatedContent);\n\n return {\n recommendation_id: rec.id,\n success: true,\n details: `Appended section: ${rec.title}`,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n recommendation_id: rec.id,\n success: false,\n details: message,\n };\n }\n }\n}\n","// Entry point for /evolve skill invocation.\n// Runs the full analysis pipeline, renders markdown recommendations,\n// writes the output file, and sets the notification flag.\n\nimport { runAnalysis } from '../analysis/trigger.js';\nimport { renderRecommendations } from './renderer.js';\nimport { getStatusMap } from './state.js';\nimport { rotateRecommendations } from './rotator.js';\nimport { writeNotificationFlag } from './notification.js';\nimport { autoApplyRecommendations } from './auto-apply.js';\nimport { paths, ensureInit } from '../storage/dirs.js';\nimport { loadConfig } from '../storage/config.js';\nimport writeFileAtomic from 'write-file-atomic';\n\n/**\n * Main entry point: runs analysis, renders output, writes recommendations file.\n * Outputs a JSON summary to stdout for the /evolve skill to present.\n */\nasync function main(): Promise<void> {\n const cwd = process.argv[2] || process.cwd();\n await ensureInit();\n\n const config = await loadConfig();\n\n // Run analysis pipeline\n const result = await runAnalysis(cwd);\n\n // Load state and build status map\n const stateMap = await getStatusMap();\n\n // Rotate old recommendations before rendering\n await rotateRecommendations({\n maxRecommendationsInFile: config.delivery.maxRecommendationsInFile,\n archiveAfterDays: config.delivery.archiveAfterDays,\n });\n\n // Render markdown\n const markdown = renderRecommendations(result, stateMap);\n await writeFileAtomic(paths.recommendations, markdown);\n\n // Auto-apply HIGH-confidence recommendations when fullAuto is enabled (DEL-06)\n try {\n await autoApplyRecommendations(result.recommendations);\n } catch {\n // Auto-apply failure must not break /evolve flow\n }\n\n // Reload state after auto-apply (applied recs change pending count)\n const updatedStateMap = await getStatusMap();\n\n // Set notification flag for pending count\n const pendingCount = result.recommendations.filter(\n (r) => (updatedStateMap.get(r.id) ?? 'pending') === 'pending',\n ).length;\n if (pendingCount > 0) {\n await writeNotificationFlag(pendingCount);\n }\n\n // Output JSON summary for the skill to present\n const pending = result.recommendations.filter(\n (r) => (updatedStateMap.get(r.id) ?? 'pending') === 'pending',\n );\n console.log(\n JSON.stringify({\n total: result.recommendations.length,\n pending: pending.length,\n high: pending.filter((r) => r.confidence === 'HIGH').length,\n medium: pending.filter((r) => r.confidence === 'MEDIUM').length,\n low: pending.filter((r) => r.confidence === 'LOW').length,\n file: paths.recommendations,\n }),\n );\n}\n\nmain().catch(() => process.exit(1));\n"],"mappings":"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","names":["readFile","writeFileAtomic","z","readFile","writeFileAtomic","join","z","z","writeFileAtomic","formatDate","readdir","readFile","join","writeFileAtomic","join","writeFileAtomic","readFile","readdir","z","readFile","readFile","writeFileAtomic","z","readFile","writeFileAtomic","z","readFile","isNodeError","writeFileAtomic","readFile","lock","writeFileAtomic","mkdir","join","writeFileAtomic","join","mkdir","writeFileAtomic","readFile","appendFile","readFile","mkdir","join","writeFileAtomic","join","readFile","mkdir","writeFileAtomic","writeFile","access","mkdir","join","writeFile","access","mkdir","copyFile","join","z","z","readFile","join","createInterface","writeFileAtomic","readFile","writeFileAtomic","join","access","mkdir","writeFile","copyFile","readFile","mkdir","join","dirname","writeFileAtomic","join","readFile","mkdir","writeFileAtomic","dirname","appendFile","writeFileAtomic"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core handler logic, exported for testability.
|
|
3
|
+
* Validates input, appends permission log entry with decision='unknown',
|
|
4
|
+
* increments counter. Swallows all errors to never block Claude Code.
|
|
5
|
+
*/
|
|
6
|
+
declare function handlePermissionRequest(rawJson: string): Promise<void>;
|
|
7
|
+
|
|
8
|
+
export { handlePermissionRequest };
|