diff --git a/dist/cli.js b/dist/cli.js deleted file mode 100755 index 03d07d3..0000000 --- a/dist/cli.js +++ /dev/null @@ -1,3129 +0,0 @@ -#!/usr/bin/env node - -// src/cli/cli.ts -import { Command } from "commander"; -import chalk13 from "chalk"; - -// src/cli/commands/dashboard.ts -import chalk2 from "chalk"; -import ora from "ora"; -import { existsSync as existsSync3 } from "fs"; - -// src/core/config.ts -import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; -import { join as join2 } from "path"; -import toml from "toml"; - -// src/core/paths.ts -import { homedir } from "os"; -import { join } from "path"; -function getClaudeProjectsDir() { - return join(homedir(), ".claude", "projects"); -} -function getDevlogDir() { - return join(homedir(), ".devlog"); -} -function getConfigPath() { - return join(getDevlogDir(), "config.toml"); -} -function decodePath(encoded) { - if (encoded.startsWith("-")) { - return encoded.replace(/-/g, "/"); - } - return encoded; -} -function getProjectName(decodedPath) { - const parts = decodedPath.split("/").filter(Boolean); - return parts[parts.length - 1] || decodedPath; -} - -// src/core/config.ts -var DEFAULT_CONFIG = `# DevLog Configuration -# Auto-generated by devlog - -[paths] -# Claude Code projects directory -claude_dir = "{{claudeDir}}" - -# DevLog data directory -devlog_dir = "{{devlogDir}}" - -[display] -# Maximum number of sessions to show in list -max_sessions = 50 - -# Truncate message preview to this length -preview_length = 80 -`; -function isInitialized() { - return existsSync(getConfigPath()); -} -function initConfig() { - const devlogDir = getDevlogDir(); - const claudeDir = getClaudeProjectsDir(); - const configPath = getConfigPath(); - mkdirSync(devlogDir, { recursive: true }); - mkdirSync(join2(devlogDir, "daily"), { recursive: true }); - mkdirSync(join2(devlogDir, "reports"), { recursive: true }); - mkdirSync(join2(devlogDir, "db"), { recursive: true }); - const configContent = DEFAULT_CONFIG.replace( - "{{claudeDir}}", - claudeDir - ).replace("{{devlogDir}}", devlogDir); - writeFileSync(configPath, configContent, "utf-8"); - return { claudeDir, devlogDir, version: "0.1.0" }; -} -function ensureInit() { - if (!isInitialized()) { - return { config: initConfig(), isFirstRun: true }; - } - return { config: loadConfig(), isFirstRun: false }; -} -function loadConfig() { - const configPath = getConfigPath(); - if (!existsSync(configPath)) { - return { - claudeDir: getClaudeProjectsDir(), - devlogDir: getDevlogDir(), - version: "0.1.0" - }; - } - try { - const raw = readFileSync(configPath, "utf-8"); - const parsed = toml.parse(raw); - return { - claudeDir: parsed.paths?.claude_dir || getClaudeProjectsDir(), - devlogDir: parsed.paths?.devlog_dir || getDevlogDir(), - version: "0.1.0" - }; - } catch { - return { - claudeDir: getClaudeProjectsDir(), - devlogDir: getDevlogDir(), - version: "0.1.0" - }; - } -} - -// src/core/discovery.ts -import { readdir, stat } from "fs/promises"; -import { join as join3 } from "path"; -import { existsSync as existsSync2 } from "fs"; - -// src/core/parser.ts -import { createReadStream } from "fs"; -import { createInterface } from "readline"; - -// src/core/pricing.ts -var PRICING = { - "claude-opus-4-7": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 }, - "claude-opus-4-6": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 }, - "claude-opus-4-5": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 }, - "claude-opus-4-1": { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.5 }, - "claude-opus-4": { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.5 }, - "claude-sonnet-4-6": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }, - "claude-sonnet-4-5-20241022": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }, - "claude-sonnet-4-5": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }, - "claude-sonnet-4": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }, - "claude-haiku-4-5": { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.1 }, - "claude-haiku-3-5": { input: 0.8, output: 4, cacheCreation: 1, cacheRead: 0.08 }, - "claude-3-5-haiku": { input: 0.8, output: 4, cacheCreation: 1, cacheRead: 0.08 } -}; -var FALLBACK = { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }; -function findPricing(model) { - if (PRICING[model]) return PRICING[model]; - for (const [key, val] of Object.entries(PRICING).sort((a, b) => b[0].length - a[0].length)) { - if (model.includes(key) || key.includes(model)) return val; - } - if (model.includes("opus")) return PRICING["claude-opus-4-6"]; - if (model.includes("haiku")) return PRICING["claude-haiku-4-5"]; - if (model.includes("sonnet")) return PRICING["claude-sonnet-4-6"]; - return FALLBACK; -} -function computeCost(model, usage) { - const p = findPricing(model); - const perM = 1e6; - let cost = 0; - cost += (usage.input_tokens || 0) * p.input / perM; - cost += (usage.output_tokens || 0) * p.output / perM; - cost += (usage.cache_creation_input_tokens || 0) * p.cacheCreation / perM; - cost += (usage.cache_read_input_tokens || 0) * p.cacheRead / perM; - return cost; -} - -// src/core/parser.ts -var SKIP_TYPES = /* @__PURE__ */ new Set([ - "progress", - "file-history-snapshot", - "queue-operation" -]); -function resolveRole(event) { - const t = event.type; - if (t === "human" || t === "user") return "human"; - if (t === "assistant") return "assistant"; - return null; -} -function getContent(event) { - if (event.message && typeof event.message === "object" && event.message.content != null) { - return event.message.content; - } - return event.content; -} -function getModel(event) { - if (event.message && typeof event.message === "object" && event.message.model) { - return event.message.model; - } - return event.model; -} -async function scanSession(filePath) { - const meta = { - messageCount: 0, - humanTurns: 0, - assistantTurns: 0, - toolCalls: 0, - uniqueTools: [], - filesReferenced: [], - totalCostUSD: 0, - totalDurationMs: 0, - models: [], - firstUserMessage: "", - lastActivity: /* @__PURE__ */ new Date(0), - firstActivity: /* @__PURE__ */ new Date(), - errorCount: 0, - costByModel: {} - }; - const toolSet = /* @__PURE__ */ new Set(); - const fileSet = /* @__PURE__ */ new Set(); - const modelSet = /* @__PURE__ */ new Set(); - const costedMessageIds = /* @__PURE__ */ new Set(); - const rl = createInterface({ - input: createReadStream(filePath, { encoding: "utf-8" }), - crlfDelay: Infinity - }); - for await (const line of rl) { - if (!line.trim()) continue; - try { - const event = JSON.parse(line); - if (SKIP_TYPES.has(event.type)) continue; - const ts = event.timestamp ? new Date(event.timestamp) : null; - if (ts) { - if (ts < meta.firstActivity) meta.firstActivity = ts; - if (ts > meta.lastActivity) meta.lastActivity = ts; - } - const role = resolveRole(event); - if (role === "human") { - meta.humanTurns++; - meta.messageCount++; - } - if (role === "assistant") { - meta.assistantTurns++; - meta.messageCount++; - } - if (role === "human" && !meta.firstUserMessage) { - meta.firstUserMessage = extractTextContent(event); - } - const model = getModel(event); - const message = event.message && typeof event.message === "object" ? event.message : void 0; - const usage = message?.usage; - const messageId = typeof message?.id === "string" ? message.id : void 0; - const shouldCountUsage = Boolean(usage) && (!messageId || !costedMessageIds.has(messageId)); - if (model && usage && shouldCountUsage) { - if (messageId) costedMessageIds.add(messageId); - const cost = computeCost(model, usage); - meta.totalCostUSD += cost; - meta.costByModel[model] = (meta.costByModel[model] || 0) + cost; - } else if (event.costUSD && typeof event.costUSD === "number") { - meta.totalCostUSD += event.costUSD; - const m = model || "unknown"; - meta.costByModel[m] = (meta.costByModel[m] || 0) + event.costUSD; - } - if (event.type === "system" && event.subtype === "turn_duration") { - const dur = event.durationMs; - if (typeof dur === "number") { - meta.totalDurationMs += dur; - } - } - if (event.durationMs && typeof event.durationMs === "number") { - meta.totalDurationMs += event.durationMs; - } - if (model) { - modelSet.add(model); - } - const content = getContent(event); - if (Array.isArray(content)) { - for (const block of content) { - if (block.type === "tool_use") { - const tb = block; - meta.toolCalls++; - toolSet.add(tb.name); - const input = tb.input; - if (input) { - for (const key of ["file_path", "path", "filePath"]) { - if (input[key] && typeof input[key] === "string") { - fileSet.add(input[key]); - } - } - } - } - if (block.type === "tool_result") { - const rb = block; - if (rb.is_error) meta.errorCount++; - } - } - } - } catch { - continue; - } - } - meta.uniqueTools = [...toolSet]; - meta.filesReferenced = [...fileSet]; - meta.models = [...modelSet]; - return meta; -} -async function parseSessionFile(filePath, sessionId) { - const events = []; - let lineIndex = 0; - const rl = createInterface({ - input: createReadStream(filePath, { encoding: "utf-8" }), - crlfDelay: Infinity - }); - for await (const line of rl) { - if (!line.trim()) continue; - lineIndex++; - try { - const raw = JSON.parse(line); - if (SKIP_TYPES.has(raw.type)) continue; - const parsed = normalizeEvent(raw, sessionId, lineIndex); - if (parsed.length > 0) { - events.push(...parsed); - } - } catch { - continue; - } - } - return events; -} -function normalizeEvent(raw, sessionId, lineIndex) { - const events = []; - const timestamp = raw.timestamp ? new Date(raw.timestamp) : /* @__PURE__ */ new Date(); - const baseId = raw.uuid || `${sessionId}-${lineIndex}`; - const role = resolveRole(raw); - const content = getContent(raw); - const model = getModel(raw); - if (role && Array.isArray(content)) { - const blocks = content; - let blockIndex = 0; - for (const block of blocks) { - blockIndex++; - const eventId = `${baseId}-${blockIndex}`; - if (block.type === "text") { - const textBlock = block; - events.push({ - id: eventId, - sessionId, - timestamp, - role, - type: "text", - content: textBlock.text, - costUSD: raw.costUSD, - durationMs: raw.durationMs, - model, - raw - }); - } else if (block.type === "tool_use") { - const toolBlock = block; - events.push({ - id: eventId, - sessionId, - timestamp, - role: "tool_use", - type: "tool_use", - content: `${toolBlock.name}(${summarizeToolInput(toolBlock.input)})`, - toolName: toolBlock.name, - toolInput: toolBlock.input, - toolUseId: toolBlock.id, - raw - }); - } else if (block.type === "tool_result") { - const resultBlock = block; - events.push({ - id: eventId, - sessionId, - timestamp, - role: "tool_result", - type: "tool_result", - content: extractToolResultContent(resultBlock), - toolUseId: resultBlock.tool_use_id, - isError: resultBlock.is_error, - raw - }); - } - } - if (typeof content === "string") { - events.push({ - id: baseId, - sessionId, - timestamp, - role, - type: "message", - content, - raw - }); - } - if (events.length === 0) { - events.push({ - id: baseId, - sessionId, - timestamp, - role, - type: "message", - content: extractTextContent(raw), - raw - }); - } - } else if (role === "human" && typeof content === "string") { - events.push({ - id: baseId, - sessionId, - timestamp, - role: "human", - type: "message", - content, - raw - }); - } else if (raw.type === "summary") { - events.push({ - id: baseId, - sessionId, - timestamp, - role: "system", - type: "summary", - content: raw.summary || "", - raw - }); - } - return events; -} -function extractTextContent(event) { - const msgContent = event.message && typeof event.message === "object" ? event.message.content : void 0; - if (typeof msgContent === "string") return msgContent; - if (Array.isArray(msgContent)) { - const textBlocks = msgContent.filter( - (b) => b.type === "text" - ); - if (textBlocks.length > 0) return textBlocks.map((b) => b.text).join("\n"); - } - if (typeof event.content === "string") return event.content; - if (Array.isArray(event.content)) { - const textBlocks = event.content.filter( - (b) => b.type === "text" - ); - if (textBlocks.length > 0) return textBlocks.map((b) => b.text).join("\n"); - } - return ""; -} -function summarizeToolInput(input) { - const parts = []; - if (input.command && typeof input.command === "string") - parts.push(truncateStr(input.command, 60)); - if (input.file_path && typeof input.file_path === "string") - parts.push(input.file_path); - if (input.path && typeof input.path === "string") - parts.push(input.path); - if (input.query && typeof input.query === "string") - parts.push(truncateStr(input.query, 40)); - if (parts.length === 0) { - return Object.keys(input).slice(0, 3).join(", "); - } - return parts.join(", "); -} -function extractToolResultContent(block) { - if (typeof block.content === "string") return block.content; - if (Array.isArray(block.content)) { - return block.content.filter((item) => item.text).map((item) => item.text).join("\n"); - } - return ""; -} -function truncateStr(str, max) { - if (str.length <= max) return str; - return str.slice(0, max - 1) + "\u2026"; -} - -// src/core/discovery.ts -import dayjs from "dayjs"; -async function discoverProjects(claudeDir, onProgress) { - const projectsDir = claudeDir || getClaudeProjectsDir(); - if (!existsSync2(projectsDir)) { - return []; - } - const entries = await readdir(projectsDir, { withFileTypes: true }); - const projects = []; - for (const entry of entries) { - if (!entry.isDirectory()) continue; - const projectDir = join3(projectsDir, entry.name); - const decodedPath = decodePath(entry.name); - const projectName = getProjectName(decodedPath); - onProgress?.(`Scanning ${projectName}...`); - const sessions = await discoverSessions( - projectDir, - decodedPath, - projectName - ); - if (sessions.length > 0) { - projects.push({ - path: decodedPath, - name: projectName, - encodedPath: entry.name, - sessionCount: sessions.length, - sessions - }); - } - } - projects.sort((a, b) => { - const aLatest = Math.max( - ...a.sessions.map((s) => s.updatedAt.getTime()) - ); - const bLatest = Math.max( - ...b.sessions.map((s) => s.updatedAt.getTime()) - ); - return bLatest - aLatest; - }); - return projects; -} -async function discoverSessions(projectDir, decodedPath, projectName) { - const sessions = []; - try { - const entries = await readdir(projectDir, { withFileTypes: true }); - for (const entry of entries) { - if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue; - const filePath = join3(projectDir, entry.name); - const sessionId = entry.name.replace(".jsonl", ""); - try { - const fileStat = await stat(filePath); - const meta = await scanSession(filePath); - const createdAt = meta.firstActivity.getTime() > 0 ? meta.firstActivity : fileStat.birthtime; - const updatedAt = meta.lastActivity.getTime() > 0 ? meta.lastActivity : fileStat.mtime; - sessions.push({ - id: sessionId, - projectPath: decodedPath, - projectName, - filePath, - createdAt, - updatedAt, - meta - }); - } catch { - continue; - } - } - } catch { - return []; - } - sessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - return sessions; -} -function computeStats(projects) { - const today = dayjs().startOf("day"); - let totalSessions = 0; - let totalMessages = 0; - let totalHumanTurns = 0; - let totalAssistantTurns = 0; - let totalToolCalls = 0; - let totalCostUSD = 0; - let totalDurationMs = 0; - let todaySessions = 0; - let todayMessages = 0; - let todayCostUSD = 0; - const allTools = /* @__PURE__ */ new Set(); - const allFiles = /* @__PURE__ */ new Set(); - const allModels = /* @__PURE__ */ new Set(); - let mostActiveProject = ""; - let mostActiveProjectSessions = 0; - for (const project of projects) { - totalSessions += project.sessionCount; - if (project.sessionCount > mostActiveProjectSessions) { - mostActiveProjectSessions = project.sessionCount; - mostActiveProject = project.name; - } - for (const session of project.sessions) { - const m = session.meta; - totalMessages += m.messageCount; - totalHumanTurns += m.humanTurns; - totalAssistantTurns += m.assistantTurns; - totalToolCalls += m.toolCalls; - totalCostUSD += m.totalCostUSD; - totalDurationMs += m.totalDurationMs; - m.uniqueTools.forEach((t) => allTools.add(t)); - m.filesReferenced.forEach((f) => allFiles.add(f)); - m.models.forEach((model) => allModels.add(model)); - if (dayjs(session.updatedAt).isAfter(today)) { - todaySessions++; - todayMessages += m.messageCount; - todayCostUSD += m.totalCostUSD; - } - } - } - return { - totalProjects: projects.length, - totalSessions, - totalMessages, - totalHumanTurns, - totalAssistantTurns, - totalToolCalls, - totalCostUSD, - totalDurationMs, - uniqueToolsUsed: [...allTools], - allFilesReferenced: [...allFiles], - modelsUsed: [...allModels], - todaySessions, - todayMessages, - todayCostUSD, - mostActiveProject, - mostActiveProjectSessions - }; -} -function groupSessionsByTime(projects) { - const now = dayjs(); - const todayStart = now.startOf("day"); - const yesterdayStart = todayStart.subtract(1, "day"); - const weekStart = now.startOf("week"); - const groups = { - today: [], - yesterday: [], - thisWeek: [], - older: [] - }; - for (const project of projects) { - for (const session of project.sessions) { - const d = dayjs(session.updatedAt); - if (d.isAfter(todayStart)) { - groups.today.push(session); - } else if (d.isAfter(yesterdayStart)) { - groups.yesterday.push(session); - } else if (d.isAfter(weekStart)) { - groups.thisWeek.push(session); - } else { - groups.older.push(session); - } - } - } - for (const group of Object.values(groups)) { - group.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - } - return groups; -} - -// src/cli/utils/format.ts -import chalk from "chalk"; -import dayjs2 from "dayjs"; -import relativeTime from "dayjs/plugin/relativeTime.js"; -import isToday from "dayjs/plugin/isToday.js"; -import isYesterday from "dayjs/plugin/isYesterday.js"; -dayjs2.extend(relativeTime); -dayjs2.extend(isToday); -dayjs2.extend(isYesterday); -function formatSmartTime(date) { - const d = dayjs2(date); - if (d.isToday()) return d.format("h:mm A"); - if (d.isYesterday()) return "Yest " + d.format("h:mm A"); - const now = dayjs2(); - const diffDays = now.diff(d, "day"); - if (diffDays < 7) return d.format("ddd h:mm A"); - return d.format("MMM D, h:mm A"); -} -function truncate(str, maxLen) { - if (str.length <= maxLen) return str; - return str.slice(0, maxLen - 1) + "\u2026"; -} -function formatNumber(n) { - return n.toLocaleString(); -} -function printSuccess(msg) { - console.log(chalk.green(" \u2713 ") + msg); -} -function printError(msg) { - console.error(chalk.red(" \u2717 ") + msg); -} -var TOOL_NAMES = { - Bash: "ran a command", - Read: "read a file", - Write: "wrote a file", - Edit: "edited a file", - Glob: "searched for files", - Grep: "searched code", - Agent: "used an agent", - WebSearch: "searched the web", - WebFetch: "fetched a page", - TodoWrite: "updated todos", - TodoRead: "checked todos" -}; -function humanizeToolName(name) { - if (TOOL_NAMES[name]) return TOOL_NAMES[name]; - return name.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase(); -} -var TOOL_PLURALS = { - Bash: { singular: "ran a command", plural: "ran commands" }, - Read: { singular: "read a file", plural: "read files" }, - Write: { singular: "wrote a file", plural: "wrote files" }, - Edit: { singular: "edited a file", plural: "edited files" }, - Glob: { singular: "searched for files", plural: "searched for files" }, - Grep: { singular: "searched code", plural: "searched code" }, - Agent: { singular: "used an agent", plural: "used agents" } -}; -function humanizeToolSummary(tools) { - const counts = /* @__PURE__ */ new Map(); - for (const t of tools) { - counts.set(t, (counts.get(t) || 0) + 1); - } - const parts = []; - for (const [name, count] of counts) { - const p = TOOL_PLURALS[name]; - if (p) { - parts.push(count === 1 ? p.singular : `${p.plural}`); - } else { - const human = humanizeToolName(name); - parts.push(count === 1 ? human : `${human} (\xD7${count})`); - } - } - if (parts.length === 0) return ""; - if (parts.length === 1) return `Claude ${parts[0]}`; - const last = parts.pop(); - return `Claude ${parts.join(", ")}, and ${last}`; -} -function costWithContext(usd) { - if (usd === 0) return chalk.dim("\u2014"); - const formatted = usd < 0.01 ? `$${usd.toFixed(4)}` : usd < 1 ? `$${usd.toFixed(3)}` : `$${usd.toFixed(2)}`; - let context = ""; - if (usd < 0.01) context = " \u2014 barely a penny"; - else if (usd < 0.05) context = " \u2014 pocket change"; - else if (usd < 0.15) context = " \u2014 pretty efficient"; - else if (usd < 0.5) context = " \u2014 a good session"; - else if (usd < 1) context = " \u2014 solid investment"; - else if (usd < 5) context = " \u2014 heavy session"; - else context = " \u2014 serious work"; - return chalk.yellow(formatted) + chalk.dim(context); -} -function messageCountContext(turns) { - if (turns <= 2) return chalk.dim("quick question"); - if (turns <= 4) return chalk.dim("quick chat"); - if (turns <= 10) return chalk.dim(`${turns} messages`); - if (turns <= 25) return chalk.white(`${turns} messages`) + chalk.dim(" \u2014 solid session"); - if (turns <= 50) return chalk.white(`${turns} messages`) + chalk.dim(" \u2014 deep dive"); - return chalk.white(`${turns} messages`) + chalk.dim(" \u2014 marathon"); -} -function fileCountContext(count) { - if (count === 0) return ""; - if (count === 1) return chalk.blue("touched 1 file"); - if (count <= 5) return chalk.blue(`touched ${count} files`); - if (count <= 15) return chalk.blue(`touched ${count} files`) + chalk.dim(" \u2014 broad changes"); - return chalk.blue(`touched ${count} files`) + chalk.dim(" \u2014 major refactor"); -} -function toolCountContext(count) { - if (count === 0) return ""; - if (count <= 10) return chalk.green(`ran ${count} commands`); - if (count <= 30) return chalk.green(`ran ${count} commands`) + chalk.dim(" \u2014 busy session"); - return chalk.green(`ran ${count} commands`) + chalk.dim(" \u2014 heavy automation"); -} -function levenshtein(a, b) { - const m = a.length; - const n = b.length; - const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); - for (let i = 0; i <= m; i++) dp[i][0] = i; - for (let j = 0; j <= n; j++) dp[0][j] = j; - for (let i = 1; i <= m; i++) { - for (let j = 1; j <= n; j++) { - dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]); - } - } - return dp[m][n]; -} - -// src/cli/utils/output.ts -var ctx = { json: false, quiet: false }; -function initOutput(opts) { - ctx = opts; -} -function outputJson(data) { - process.stdout.write(JSON.stringify(data, null, 2) + "\n"); -} -function isJsonMode() { - return ctx.json; -} -function isQuietMode() { - return ctx.quiet; -} - -// src/cli/commands/shared.ts -function toSessionJson(session) { - return { - id: session.id, - projectName: session.projectName, - projectPath: session.projectPath, - createdAt: session.createdAt.toISOString(), - updatedAt: session.updatedAt.toISOString(), - messageCount: session.meta.messageCount, - toolCalls: session.meta.toolCalls, - filesTouched: session.meta.filesReferenced.length, - costUSD: Math.round(session.meta.totalCostUSD * 1e6) / 1e6, - firstMessage: session.meta.firstUserMessage - }; -} - -// src/core/cache.ts -import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2 } from "fs"; -import { join as join4, dirname } from "path"; -import dayjs3 from "dayjs"; -var CACHE_FILENAME = "stats-cache.json"; -var DEFAULT_MAX_AGE_MS = 5 * 60 * 1e3; -function getCachePath() { - return join4(getDevlogDir(), "db", CACHE_FILENAME); -} -function readStatsCache() { - try { - const raw = readFileSync2(getCachePath(), "utf-8"); - return JSON.parse(raw); - } catch { - return null; - } -} -function writeStatsCache(cache) { - const cachePath = getCachePath(); - const tmpPath = cachePath + ".tmp"; - try { - mkdirSync2(dirname(cachePath), { recursive: true }); - writeFileSync2(tmpPath, JSON.stringify(cache, null, 2), "utf-8"); - renameSync(tmpPath, cachePath); - } catch { - } -} -function isCacheFresh(cache, maxAgeMs) { - const maxAge = maxAgeMs ?? DEFAULT_MAX_AGE_MS; - const todayStr = dayjs3().format("YYYY-MM-DD"); - if (cache.todayDate !== todayStr) return false; - const age = Date.now() - new Date(cache.timestamp).getTime(); - return age < maxAge; -} -function updateCacheFromStats(stats) { - const now = dayjs3(); - const cache = { - timestamp: now.toISOString(), - todayDate: now.format("YYYY-MM-DD"), - today: { - sessions: stats.todaySessions, - costUSD: stats.todayCostUSD, - messages: stats.todayMessages, - toolCalls: stats.totalToolCalls, - // approx — full stats don't split today's tool calls - filesTouched: stats.allFilesReferenced.length, - projects: stats.mostActiveProject ? [stats.mostActiveProject] : [] - }, - allTime: { - sessions: stats.totalSessions, - costUSD: stats.totalCostUSD, - projects: stats.totalProjects - } - }; - writeStatsCache(cache); -} - -// src/cli/commands/dashboard.ts -var VERSION = "0.4.0"; -async function dashboardCommand(globalOpts) { - const { config, isFirstRun } = ensureInit(); - if (!existsSync3(config.claudeDir)) { - if (isJsonMode()) { - outputJson({ error: "Claude Code not found", path: getClaudeProjectsDir() }); - process.exit(1); - } - console.log(); - console.log( - chalk2.bold.cyan(" \u258C") + chalk2.bold.white(" DevLog") - ); - console.log(); - console.log( - chalk2.white(" Hmm, I can't find Claude Code on this machine.") - ); - console.log( - chalk2.dim(" I looked for: ") + chalk2.white(getClaudeProjectsDir()) - ); - console.log(); - console.log( - chalk2.white(" To get started:") - ); - console.log( - chalk2.dim(" 1. Install Claude Code \u2192 ") + chalk2.cyan("https://claude.ai/code") - ); - console.log( - chalk2.dim(" 2. Have a conversation with Claude in any project") - ); - console.log( - chalk2.dim(" 3. Come back and run ") + chalk2.cyan("devlog") + chalk2.dim(" again") - ); - console.log(); - return; - } - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora({ - text: chalk2.dim(" Reading your Claude Code history..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir, (msg) => { - if (spinner) spinner.text = chalk2.dim(` ${msg}`); - }); - spinner?.stop(); - if (projects.length === 0) { - if (isJsonMode()) { - outputJson({ version: VERSION, timestamp: (/* @__PURE__ */ new Date()).toISOString(), summary: "No sessions found", stats: { totalProjects: 0, totalSessions: 0, totalToolCalls: 0, totalFilesTouched: 0, totalCostUSD: 0, todaySessions: 0, todayCostUSD: 0 }, recentSessions: [] }); - return; - } - console.log(); - console.log( - chalk2.bold.cyan(" \u258C") + chalk2.bold.white(" DevLog") - ); - console.log(); - console.log( - chalk2.white(" No conversations found yet.") - ); - console.log( - chalk2.dim(" Start a Claude Code session in any project, then come back!") - ); - console.log(); - return; - } - const stats = computeStats(projects); - updateCacheFromStats(stats); - const groups = groupSessionsByTime(projects); - if (isJsonMode()) { - const allSessions = projects.flatMap((p) => p.sessions); - allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - const recent = allSessions.slice(0, 10); - const projectWord = stats.totalProjects === 1 ? "project" : "projects"; - const sessionWord = stats.totalSessions === 1 ? "conversation" : "conversations"; - const data = { - version: VERSION, - timestamp: (/* @__PURE__ */ new Date()).toISOString(), - summary: `You and Claude had ${stats.totalSessions} ${sessionWord} across ${stats.totalProjects} ${projectWord}`, - stats: { - totalProjects: stats.totalProjects, - totalSessions: stats.totalSessions, - totalToolCalls: stats.totalToolCalls, - totalFilesTouched: stats.allFilesReferenced.length, - totalCostUSD: Math.round(stats.totalCostUSD * 1e6) / 1e6, - todaySessions: stats.todaySessions, - todayCostUSD: Math.round(stats.todayCostUSD * 1e6) / 1e6 - }, - recentSessions: recent.map(toSessionJson) - }; - outputJson(data); - return; - } - console.log(); - if (!isQuietMode()) { - if (isFirstRun) { - renderWelcome(stats); - } else { - renderBanner(); - } - } - renderNarrativeStats(stats); - renderSessionGroups(groups, stats); - if (!isQuietMode()) { - renderNextSteps(stats, isFirstRun); - } -} -function renderWelcome(stats) { - console.log( - chalk2.bold.cyan(" \u258C") + chalk2.bold.white(" Welcome to DevLog!") - ); - console.log(); - console.log( - chalk2.white(" I found your Claude Code history \u2014 let me show you what") + chalk2.white(" you've been building.") - ); - console.log(); -} -function renderBanner() { - console.log( - chalk2.bold.cyan(" \u258C") + chalk2.bold.white(" DevLog") - ); - console.log(); -} -function renderNarrativeStats(stats) { - const projectWord = stats.totalProjects === 1 ? "project" : "projects"; - const sessionWord = stats.totalSessions === 1 ? "conversation" : "conversations"; - console.log( - chalk2.dim(" ") + chalk2.white("You and Claude had ") + chalk2.cyan.bold(String(stats.totalSessions)) + chalk2.white(` ${sessionWord} across `) + chalk2.cyan.bold(String(stats.totalProjects)) + chalk2.white(` ${projectWord}.`) - ); - const activityParts = []; - if (stats.totalToolCalls > 0) { - activityParts.push( - chalk2.white("Claude ran ") + chalk2.green.bold(formatNumber(stats.totalToolCalls)) + chalk2.white(" commands") - ); - } - if (stats.allFilesReferenced.length > 0) { - activityParts.push( - chalk2.white("touched ") + chalk2.blue.bold(String(stats.allFilesReferenced.length)) + chalk2.white(" files") - ); - } - if (activityParts.length > 0) { - console.log(chalk2.dim(" ") + activityParts.join(chalk2.dim(" and "))); - } - if (stats.totalCostUSD > 0) { - const costStr = stats.totalCostUSD < 1 ? `$${stats.totalCostUSD.toFixed(3)}` : `$${stats.totalCostUSD.toFixed(2)}`; - let costContext = ""; - if (stats.totalCostUSD < 0.1) costContext = " \u2014 less than a cup of coffee"; - else if (stats.totalCostUSD < 1) costContext = " \u2014 pretty efficient"; - else if (stats.totalCostUSD < 5) costContext = " \u2014 solid investment"; - console.log( - chalk2.dim(" ") + chalk2.white("Total cost: ") + chalk2.yellow.bold(costStr) + chalk2.dim(costContext) - ); - } - if (stats.todaySessions > 0) { - const todayWord = stats.todaySessions === 1 ? "session" : "sessions"; - console.log( - chalk2.dim(" ") + chalk2.green("\u25B8 ") + chalk2.white.bold(`${stats.todaySessions} ${todayWord} today`) + (stats.todayCostUSD > 0 ? chalk2.dim(` \xB7 $${stats.todayCostUSD.toFixed(3)}`) : "") - ); - } - console.log(); - console.log(chalk2.dim(" " + "\u2500".repeat(60))); - console.log(); -} -function renderSessionGroups(groups, stats) { - const hasToday = groups.today.length > 0; - const hasYesterday = groups.yesterday.length > 0; - const hasThisWeek = groups.thisWeek.length > 0; - const hasOlder = groups.older.length > 0; - if (hasToday) { - renderGroup("Today", groups.today, chalk2.green); - } - if (hasYesterday) { - renderGroup("Yesterday", groups.yesterday, chalk2.blue); - } - if (hasThisWeek) { - renderGroup("This Week", groups.thisWeek, chalk2.white); - } - if (hasOlder) { - const count = groups.older.length; - console.log( - chalk2.dim(` + ${count} older session${count === 1 ? "" : "s"}`) - ); - console.log(); - } - if (!hasToday && !hasYesterday && !hasThisWeek && !hasOlder) { - console.log(chalk2.dim(" No sessions found.")); - console.log(); - } -} -function renderGroup(label, sessions, accentColor) { - console.log(accentColor.bold(` ${label}`)); - console.log(); - for (const session of sessions) { - renderSessionCard(session, accentColor); - } -} -function renderSessionCard(session, accentColor) { - const m = session.meta; - const time = formatSmartTime(session.updatedAt); - const preview = m.firstUserMessage ? truncate(m.firstUserMessage.replace(/\n/g, " ").trim(), 50) : chalk2.dim("(empty session)"); - const timeStr = time.length > 14 ? time.slice(0, 14) : time; - console.log( - chalk2.dim(" ") + accentColor(timeStr.padEnd(16)) + chalk2.bold.white(session.projectName.padEnd(14)) + chalk2.white(preview) - ); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls)); - if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - if (m.errorCount > 0) { - const errWord = m.errorCount === 1 ? "error" : "errors"; - parts.push(chalk2.red(`${m.errorCount} ${errWord}`)); - } - console.log( - chalk2.dim(" ") + " ".repeat(30) + parts.join(chalk2.dim(" \xB7 ")) - ); - console.log(); -} -function renderNextSteps(stats, isFirstRun) { - console.log(chalk2.dim(" " + "\u2500".repeat(60))); - console.log(); - if (isFirstRun) { - console.log(chalk2.white(" What you can do next:")); - console.log(); - console.log( - chalk2.cyan(" devlog today") + chalk2.dim(" What did I do today?") - ); - console.log( - chalk2.cyan(" devlog sessions") + chalk2.dim(" Browse all sessions by project") - ); - console.log( - chalk2.cyan(" devlog show ") + chalk2.dim(" View a full conversation") - ); - console.log( - chalk2.cyan(' devlog search "auth"') + chalk2.dim(" Find a conversation") - ); - console.log(); - console.log( - chalk2.dim(" Tip: Just run ") + chalk2.cyan("devlog") + chalk2.dim(" anytime to see this dashboard.") - ); - } else { - console.log( - chalk2.dim(" ") + chalk2.cyan("devlog today") + chalk2.dim(" today \xB7 ") + chalk2.cyan("devlog sessions") + chalk2.dim(" all \xB7 ") + chalk2.cyan("devlog show ") + chalk2.dim(" view \xB7 ") + chalk2.cyan("devlog search") + chalk2.dim(" find") - ); - } - console.log(); -} - -// src/cli/commands/init.ts -import { existsSync as existsSync4 } from "fs"; -import chalk3 from "chalk"; -import ora2 from "ora"; -async function initCommand(globalOpts) { - if (!isJsonMode()) { - console.log(); - console.log( - chalk3.bold.cyan(" \u258C") + chalk3.bold.white(" DevLog Setup") - ); - console.log(); - } - if (isInitialized()) { - const config2 = loadConfig(); - let spinner2 = null; - if (!isJsonMode() && !isQuietMode()) { - printSuccess("DevLog is already set up"); - console.log( - chalk3.dim(" Config: ") + chalk3.white(getDevlogDir() + "/config.toml") - ); - console.log( - chalk3.dim(" Claude: ") + chalk3.white(config2.claudeDir) - ); - console.log(); - spinner2 = ora2({ - text: chalk3.dim(" Checking your sessions..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects2 = await discoverProjects(config2.claudeDir); - const stats2 = computeStats(projects2); - spinner2?.stop(); - if (isJsonMode()) { - outputJson({ status: "already_initialized", configPath: getDevlogDir() + "/config.toml", stats: { totalProjects: stats2.totalProjects, totalSessions: stats2.totalSessions, totalMessages: stats2.totalMessages } }); - return; - } - renderStatsBox(stats2); - console.log( - chalk3.dim(" Everything looks good! Run ") + chalk3.cyan("devlog") + chalk3.dim(" to see your dashboard.") - ); - console.log(); - return; - } - const claudeDir = getClaudeProjectsDir(); - if (!existsSync4(claudeDir)) { - if (isJsonMode()) { - outputJson({ error: "Claude Code not found", path: claudeDir }); - process.exit(1); - } - printError("Claude Code not found"); - console.log(); - console.log( - chalk3.white(" I looked for: ") + chalk3.dim("~/.claude/projects/") - ); - console.log(); - console.log(chalk3.white(" To get started:")); - console.log( - chalk3.dim(" 1. Install Claude Code \u2192 ") + chalk3.cyan("https://claude.ai/code") - ); - console.log( - chalk3.dim(" 2. Have a conversation with Claude in any project") - ); - console.log( - chalk3.dim(" 3. Come back and run ") + chalk3.cyan("devlog") + chalk3.dim(" again") - ); - console.log(); - return; - } - if (!isJsonMode()) { - printSuccess("Found Claude Code"); - } - const config = initConfig(); - if (!isJsonMode()) { - printSuccess("Created config at " + chalk3.dim("~/.devlog/")); - } - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora2({ - text: chalk3.dim(" Scanning your Claude Code history..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - const stats = computeStats(projects); - spinner?.stop(); - if (isJsonMode()) { - outputJson({ status: "initialized", configPath: getDevlogDir() + "/config.toml", stats: { totalProjects: stats.totalProjects, totalSessions: stats.totalSessions, totalMessages: stats.totalMessages } }); - return; - } - printSuccess("Scan complete"); - console.log(); - renderStatsBox(stats); - console.log( - chalk3.white(" You're all set! Run ") + chalk3.cyan.bold("devlog") + chalk3.white(" to see your dashboard.") - ); - console.log(); -} -function renderStatsBox(stats) { - const w = 42; - const line = (label, value) => { - const padding = w - label.length - value.length - 6; - return chalk3.dim(" \u2502 ") + chalk3.white(label) + " ".repeat(Math.max(1, padding)) + chalk3.cyan.bold(value) + chalk3.dim(" \u2502"); - }; - const costStr = stats.totalCostUSD > 0 ? stats.totalCostUSD < 1 ? `$${stats.totalCostUSD.toFixed(3)}` : `$${stats.totalCostUSD.toFixed(2)}` : ""; - console.log(chalk3.dim(" \u250C" + "\u2500".repeat(w) + "\u2510")); - console.log(line("Projects", formatNumber(stats.totalProjects))); - console.log(line("Conversations", formatNumber(stats.totalSessions))); - console.log(line("Messages", formatNumber(stats.totalMessages))); - console.log(line("Commands run", formatNumber(stats.totalToolCalls))); - console.log( - line("Files touched", formatNumber(stats.allFilesReferenced.length)) - ); - if (costStr) { - console.log(line("Total cost", costStr)); - } - console.log(chalk3.dim(" \u2514" + "\u2500".repeat(w) + "\u2518")); - console.log(); -} - -// src/cli/commands/sessions.ts -import chalk4 from "chalk"; -import ora3 from "ora"; -async function sessionsCommand(options, globalOpts) { - const { config, isFirstRun } = ensureInit(); - const limit = options.all ? Infinity : parseInt(options.limit || "30", 10); - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora3({ - text: chalk4.dim(" Scanning sessions..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - const stats = computeStats(projects); - spinner?.stop(); - if (projects.length === 0) { - if (isJsonMode()) { - outputJson({ projects: [] }); - return; - } - console.log(); - console.log(chalk4.white(" No sessions found yet.")); - console.log( - chalk4.dim(" Start a Claude Code session in any project, then come back!") - ); - console.log(); - return; - } - const filteredProjects = options.project ? projects.filter( - (p) => p.name.toLowerCase().includes(options.project.toLowerCase()) || p.path.toLowerCase().includes(options.project.toLowerCase()) - ) : projects; - if (isJsonMode()) { - const data = { - projects: filteredProjects.map((p) => ({ - name: p.name, - path: p.path, - sessionCount: p.sessionCount, - sessions: p.sessions.map(toSessionJson) - })) - }; - outputJson(data); - return; - } - if (filteredProjects.length === 0) { - console.log(); - console.log( - chalk4.yellow(" No projects matching ") + chalk4.white(`"${options.project}"`) - ); - console.log(); - console.log(chalk4.white(" Your projects:")); - for (const p of projects) { - console.log( - chalk4.cyan(` ${p.name}`) + chalk4.dim(` \u2014 ${p.sessionCount} session${p.sessionCount === 1 ? "" : "s"}`) - ); - } - console.log(); - console.log( - chalk4.dim(" Try: ") + chalk4.cyan(`devlog sessions -p ${projects[0].name}`) - ); - console.log(); - return; - } - console.log(); - console.log( - chalk4.bold.cyan(" \u258C") + chalk4.bold.white(" All Sessions") + (options.project ? chalk4.dim(` matching "${options.project}"`) : "") - ); - console.log( - chalk4.dim( - ` ${formatNumber(stats.totalProjects)} projects \xB7 ${formatNumber(stats.totalSessions)} conversations \xB7 ${formatNumber(stats.totalMessages)} messages` - ) - ); - console.log(); - if (isFirstRun) { - console.log( - chalk4.dim(" Each project shows your Claude conversations, newest first.") - ); - console.log( - chalk4.dim(" Pick one with ") + chalk4.cyan("devlog show ") + chalk4.dim(" to see the full chat.") - ); - console.log(); - } - let displayedCount = 0; - let sessionIndex = 0; - for (const project of filteredProjects) { - if (displayedCount >= limit) break; - const sessionWord = project.sessionCount === 1 ? "session" : "sessions"; - console.log( - chalk4.bold.white(" \u{1F4C1} " + project.name) + chalk4.dim(` \u2014 ${project.sessionCount} ${sessionWord}`) - ); - console.log(chalk4.dim(" " + project.path)); - console.log(); - const sessionsToShow = project.sessions.slice(0, limit - displayedCount); - for (const session of sessionsToShow) { - sessionIndex++; - renderSessionRow(session, sessionIndex); - displayedCount++; - } - if (project.sessions.length > sessionsToShow.length) { - const remaining = project.sessions.length - sessionsToShow.length; - console.log( - chalk4.dim(` + ${remaining} more \u2014 use `) + chalk4.cyan("--all") + chalk4.dim(" to show all") - ); - console.log(); - } - } - console.log(chalk4.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk4.dim(" ") + chalk4.cyan("devlog show 1") + chalk4.dim(" view most recent \xB7 ") + chalk4.cyan("devlog sessions -p ") + chalk4.dim(" filter") - ); - console.log(); -} -function renderSessionRow(session, index) { - const m = session.meta; - const time = formatSmartTime(session.updatedAt); - const preview = m.firstUserMessage ? truncate(m.firstUserMessage.replace(/\n/g, " ").trim(), 46) : chalk4.dim("(empty)"); - const indexStr = chalk4.dim(`${index}.`.padEnd(4)); - console.log( - chalk4.dim(" ") + indexStr + chalk4.white(time.padEnd(16)) + chalk4.white(preview) - ); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls)); - if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - if (m.errorCount > 0) { - parts.push(chalk4.red(`${m.errorCount} error${m.errorCount === 1 ? "" : "s"}`)); - } - console.log( - chalk4.dim(" ") + " " + " ".repeat(16) + parts.join(chalk4.dim(" \xB7 ")) - ); - console.log(); -} - -// src/cli/commands/show.ts -import chalk5 from "chalk"; -import ora4 from "ora"; -async function showCommand(sessionRef, options, globalOpts) { - const { config } = ensureInit(); - const limit = parseInt(options.limit || "50", 10); - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora4({ - text: chalk5.dim(" Finding session..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - spinner?.stop(); - const allSessions = []; - for (const project of projects) { - allSessions.push(...project.sessions); - } - allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - if (allSessions.length === 0) { - if (isJsonMode()) { - outputJson({ error: "No sessions found" }); - process.exit(1); - } - console.log(); - console.log(chalk5.yellow(" No sessions found.")); - console.log(); - return; - } - let session; - const asNumber = parseInt(sessionRef, 10); - if (!isNaN(asNumber) && asNumber >= 1 && asNumber <= allSessions.length) { - session = allSessions[asNumber - 1]; - } else { - const ref = sessionRef.toLowerCase(); - session = allSessions.find( - (s) => s.id.toLowerCase().startsWith(ref) - ); - if (!session) { - session = allSessions.find( - (s) => s.id.toLowerCase().includes(ref) - ); - } - } - if (!session) { - if (isJsonMode()) { - outputJson({ error: `No session matching: ${sessionRef}` }); - process.exit(1); - } - console.log(); - console.log( - chalk5.yellow(" Couldn't find a session matching: ") + chalk5.white(sessionRef) - ); - console.log(); - console.log(chalk5.dim(" Recent sessions:")); - const recent = allSessions.slice(0, 5); - recent.forEach((s, i) => { - const preview = s.meta.firstUserMessage ? truncate(s.meta.firstUserMessage.replace(/\n/g, " ").trim(), 40) : "(empty)"; - console.log( - chalk5.cyan(` ${i + 1}. `) + chalk5.white(s.projectName.padEnd(14)) + chalk5.dim(preview) + chalk5.dim(` [${s.id.slice(0, 8)}]`) - ); - }); - console.log(); - console.log( - chalk5.dim(" Use ") + chalk5.cyan("devlog show 1") + chalk5.dim(" to view the most recent session.") - ); - console.log(); - process.exit(1); - } - let parseSpinner = null; - if (!isJsonMode() && !isQuietMode()) { - parseSpinner = ora4({ - text: chalk5.dim(" Reading conversation..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const events = await parseSessionFile(session.filePath, session.id); - parseSpinner?.stop(); - if (isJsonMode()) { - const data = { - session: { - id: session.id, - projectName: session.projectName, - meta: session.meta - }, - events: events.map((e) => ({ - timestamp: e.timestamp.toISOString(), - role: e.role, - type: e.type, - content: e.content, - ...e.toolName ? { toolName: e.toolName } : {}, - ...e.isError ? { isError: e.isError } : {} - })) - }; - outputJson(data); - return; - } - if (options.summary) { - renderSummary(session, events); - } else { - renderSessionHeader(session); - renderConversation(events, limit); - renderSessionFooter(session, events, limit); - } -} -function renderSessionHeader(session) { - const m = session.meta; - console.log(); - console.log( - chalk5.bold.cyan(" \u258C") + chalk5.bold.white(` ${session.projectName}`) + chalk5.dim(" \xB7 ") + chalk5.dim(formatSmartTime(session.updatedAt)) - ); - console.log(); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls)); - if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - console.log(chalk5.dim(" ") + parts.join(chalk5.dim(" \xB7 "))); - if (m.uniqueTools.length > 0) { - console.log( - chalk5.dim(" ") + humanizeToolSummary(m.uniqueTools) - ); - } - console.log(); - console.log(chalk5.dim(" " + "\u2500".repeat(60))); - console.log(); -} -function formatToolLine(event) { - const name = event.toolName || "tool"; - const input = event.toolInput || {}; - if (name === "Read" && input.file_path) return `read ${input.file_path}`; - if (name === "Write" && input.file_path) return `wrote ${input.file_path}`; - if (name === "Edit" && input.file_path) return `edited ${input.file_path}`; - if (name === "Bash" && input.command) return `ran: ${truncate(String(input.command), 60)}`; - if (name === "Grep" && input.pattern) return `searched for "${truncate(String(input.pattern), 40)}"`; - if (name === "Glob" && input.pattern) return `found files matching ${truncate(String(input.pattern), 40)}`; - return name.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase(); -} -function flushToolGroup(group) { - if (group.length === 0) return; - const firstName = group[0].toolName || "tool"; - const allSame = group.every((e) => e.toolName === firstName); - if (allSame && group.length > 2 && (firstName === "Read" || firstName === "Write" || firstName === "Edit")) { - const verb = firstName === "Read" ? "read" : firstName === "Write" ? "wrote" : "edited"; - const files = group.map((e) => { - const p = String(e.toolInput?.file_path || ""); - return p.split("/").pop() || p; - }).filter(Boolean); - const fileWord = group.length === 1 ? "file" : "files"; - console.log( - chalk5.green(" \u25B8 ") + chalk5.dim(`${verb} ${group.length} ${fileWord}: ${truncate(files.join(", "), 60)}`) - ); - } else { - for (const event of group) { - console.log( - chalk5.green(" \u25B8 ") + chalk5.dim(formatToolLine(event)) - ); - } - } -} -function renderConversation(events, limit) { - let shown = 0; - let toolGroup = []; - for (const event of events) { - if (shown >= limit) break; - if (event.role !== "tool_use" && event.role !== "tool_result" && toolGroup.length > 0) { - flushToolGroup(toolGroup); - toolGroup = []; - } - if (event.role === "human" && (event.type === "text" || event.type === "message")) { - console.log( - chalk5.blue.bold(" You: ") + chalk5.white(truncate(event.content.trim(), 76)) - ); - console.log(); - shown++; - } else if (event.role === "assistant" && event.type === "text") { - const lines = event.content.trim().split("\n"); - const preview = lines.slice(0, 3); - console.log(chalk5.dim.bold(" Claude: ")); - for (const line of preview) { - console.log(chalk5.dim(" ") + chalk5.white(truncate(line, 74))); - } - if (lines.length > 3) { - console.log(chalk5.dim(` ... (${lines.length - 3} more lines)`)); - } - console.log(); - shown++; - } else if (event.role === "tool_use") { - toolGroup.push(event); - shown++; - } else if (event.role === "tool_result") { - if (event.isError) { - console.log( - chalk5.red(" \u2717 Error: ") + chalk5.dim(truncate(event.content, 60)) - ); - } - } - } - if (toolGroup.length > 0) { - flushToolGroup(toolGroup); - } -} -function renderSessionFooter(session, events, limit) { - const totalEvents = events.filter( - (e) => e.role === "human" && (e.type === "text" || e.type === "message") || e.role === "assistant" && e.type === "text" || e.role === "tool_use" - ).length; - console.log(); - console.log(chalk5.dim(" " + "\u2500".repeat(60))); - if (totalEvents > limit) { - console.log( - chalk5.dim(` Showing ${limit} of ${totalEvents} events. Use `) + chalk5.cyan(`devlog show ${session.id.slice(0, 8)} -n ${totalEvents}`) + chalk5.dim(" to see all.") - ); - } - console.log(); - console.log( - chalk5.dim(" ") + chalk5.cyan(`devlog sessions -p ${session.projectName}`) + chalk5.dim(" other sessions in this project") - ); - console.log( - chalk5.dim(" ") + chalk5.cyan("devlog") + chalk5.dim(" back to dashboard") - ); - console.log(); -} -function renderSummary(session, events) { - const m = session.meta; - console.log(); - console.log( - chalk5.bold.cyan(" \u258C") + chalk5.bold.white(` ${session.projectName}`) + chalk5.dim(" \xB7 ") + chalk5.dim(formatSmartTime(session.updatedAt)) - ); - console.log(); - const firstMsg = m.firstUserMessage ? truncate(m.firstUserMessage.replace(/\n/g, " ").trim(), 70) : "(empty)"; - console.log(chalk5.white(" Summary:")); - console.log( - chalk5.dim(" You asked Claude: ") + chalk5.white(`"${firstMsg}"`) - ); - console.log(); - const toolGroups = /* @__PURE__ */ new Map(); - const filesChanged = /* @__PURE__ */ new Set(); - const commandsRun = []; - let errorCount = 0; - for (const event of events) { - if (event.role === "tool_use") { - const name = event.toolName || "tool"; - toolGroups.set(name, (toolGroups.get(name) || 0) + 1); - const input = event.toolInput || {}; - if (input.file_path && (name === "Write" || name === "Edit")) { - filesChanged.add(String(input.file_path)); - } - if (name === "Bash" && input.command) { - commandsRun.push(truncate(String(input.command), 50)); - } - } - if (event.role === "tool_result" && event.isError) { - errorCount++; - } - } - console.log(chalk5.white(" What happened:")); - for (const [name, count] of toolGroups) { - let desc; - if (name === "Read") desc = `Read ${count} file${count === 1 ? "" : "s"} to understand the codebase`; - else if (name === "Write") desc = `Created ${count} file${count === 1 ? "" : "s"}`; - else if (name === "Edit") desc = `Edited ${count} file${count === 1 ? "" : "s"}`; - else if (name === "Bash") desc = `Ran ${count} command${count === 1 ? "" : "s"}` + (commandsRun.length > 0 ? ` (${truncate(commandsRun.slice(0, 3).join(", "), 40)})` : ""); - else if (name === "Grep") desc = `Searched code ${count} time${count === 1 ? "" : "s"}`; - else if (name === "Glob") desc = `Searched for files ${count} time${count === 1 ? "" : "s"}`; - else desc = `${name} \xD7${count}`; - console.log(chalk5.dim(" - ") + chalk5.dim(desc)); - } - if (filesChanged.size > 0) { - const fileNames = [...filesChanged].map((f) => f.split("/").pop() || f); - console.log( - chalk5.dim(" - ") + chalk5.dim(`Files changed: ${truncate(fileNames.join(", "), 50)}`) - ); - } - if (errorCount > 0) { - console.log( - chalk5.dim(" - ") + chalk5.red(`Fixed ${errorCount} error${errorCount === 1 ? "" : "s"}`) - ); - } - console.log(); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls)); - if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - console.log(chalk5.dim(" ") + parts.join(chalk5.dim(" \xB7 "))); - console.log(); - console.log(chalk5.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk5.dim(" ") + chalk5.cyan(`devlog show ${session.id.slice(0, 8)}`) + chalk5.dim(" see full conversation \xB7 ") + chalk5.cyan(`devlog sessions -p ${session.projectName}`) + chalk5.dim(" other sessions") - ); - console.log(); -} - -// src/cli/commands/today.ts -import chalk6 from "chalk"; -import ora5 from "ora"; -import dayjs4 from "dayjs"; -import isToday2 from "dayjs/plugin/isToday.js"; -dayjs4.extend(isToday2); -async function todayCommand(globalOpts) { - const { config } = ensureInit(); - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora5({ - text: chalk6.dim(" Checking today's sessions..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - spinner?.stop(); - const todaySessions = []; - const projectNames = /* @__PURE__ */ new Set(); - for (const project of projects) { - for (const session of project.sessions) { - if (dayjs4(session.updatedAt).isToday()) { - todaySessions.push(session); - projectNames.add(session.projectName); - } - } - } - todaySessions.sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime()); - if (isJsonMode()) { - const totalCost2 = todaySessions.reduce((s, sess) => s + sess.meta.totalCostUSD, 0); - const totalTools2 = todaySessions.reduce((s, sess) => s + sess.meta.toolCalls, 0); - const allFiles2 = /* @__PURE__ */ new Set(); - for (const s of todaySessions) { - for (const f of s.meta.filesReferenced) allFiles2.add(f); - } - outputJson({ - date: dayjs4().format("YYYY-MM-DD"), - sessionCount: todaySessions.length, - projectCount: projectNames.size, - totalCostUSD: Math.round(totalCost2 * 1e6) / 1e6, - totalToolCalls: totalTools2, - totalFilesTouched: allFiles2.size, - sessions: todaySessions.map(toSessionJson) - }); - return; - } - if (todaySessions.length === 0) { - console.log(); - console.log( - chalk6.bold.cyan(" \u258C") + chalk6.bold.white(" Your day so far") - ); - console.log(); - console.log(chalk6.dim(" No sessions yet today.")); - const allSessions = []; - for (const p of projects) allSessions.push(...p.sessions); - allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - if (allSessions.length > 0) { - const last = allSessions[0]; - console.log( - chalk6.dim(" Your last session was ") + chalk6.white(formatSmartTime(last.updatedAt)) + chalk6.dim(" in ") + chalk6.cyan(last.projectName) - ); - } - console.log(); - console.log( - chalk6.dim(" ") + chalk6.cyan("devlog sessions") + chalk6.dim(" browse all \xB7 ") + chalk6.cyan("devlog") + chalk6.dim(" dashboard") - ); - console.log(); - return; - } - const totalCost = todaySessions.reduce((s, sess) => s + sess.meta.totalCostUSD, 0); - const totalTools = todaySessions.reduce((s, sess) => s + sess.meta.toolCalls, 0); - const allFiles = /* @__PURE__ */ new Set(); - for (const s of todaySessions) { - for (const f of s.meta.filesReferenced) allFiles.add(f); - } - const sessionWord = todaySessions.length === 1 ? "conversation" : "conversations"; - const projectWord = projectNames.size === 1 ? "project" : "projects"; - console.log(); - console.log( - chalk6.bold.cyan(" \u258C") + chalk6.bold.white(" Your day so far") - ); - console.log(); - console.log( - chalk6.dim(" ") + chalk6.white(`${todaySessions.length} ${sessionWord} across ${projectNames.size} ${projectWord}.`) - ); - const summaryParts = []; - if (totalTools > 0) summaryParts.push(toolCountContext(totalTools)); - if (allFiles.size > 0) summaryParts.push(fileCountContext(allFiles.size)); - if (summaryParts.length > 0) { - console.log(chalk6.dim(" ") + chalk6.white("Claude ") + summaryParts.join(chalk6.dim(" and "))); - } - if (totalCost > 0) { - console.log(chalk6.dim(" Cost: ") + costWithContext(totalCost)); - } - console.log(); - console.log(chalk6.dim(" " + "\u2500".repeat(60))); - console.log(); - for (const session of todaySessions) { - const m = session.meta; - const time = formatSmartTime(session.updatedAt); - const preview = m.firstUserMessage ? truncate(m.firstUserMessage.replace(/\n/g, " ").trim(), 42) : chalk6.dim("(empty)"); - console.log( - chalk6.dim(" ") + chalk6.white(time.padEnd(12)) + chalk6.cyan(session.projectName.padEnd(14)) + chalk6.white(`"${preview}"`) - ); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - console.log( - chalk6.dim(" ") + " ".repeat(26) + parts.join(chalk6.dim(" \xB7 ")) - ); - console.log(); - } - console.log(chalk6.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk6.dim(" ") + chalk6.cyan("devlog show 1") + chalk6.dim(" view most recent \xB7 ") + chalk6.cyan("devlog sessions") + chalk6.dim(" browse all") - ); - console.log(); -} - -// src/cli/commands/search.ts -import chalk7 from "chalk"; -import ora6 from "ora"; -async function searchCommand(query, globalOpts) { - const { config } = ensureInit(); - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora6({ - text: chalk7.dim(" Searching sessions..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - spinner?.stop(); - const q = query.toLowerCase(); - const matches = []; - for (const project of projects) { - for (const session of project.sessions) { - const m = session.meta; - if (session.projectName.toLowerCase().includes(q) || m.firstUserMessage.toLowerCase().includes(q) || m.uniqueTools.some((t) => t.toLowerCase().includes(q))) { - matches.push(session); - } - } - } - matches.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); - if (isJsonMode()) { - outputJson({ - query, - matchCount: matches.length, - sessions: matches.map(toSessionJson) - }); - return; - } - console.log(); - console.log( - chalk7.bold.cyan(" \u258C") + chalk7.bold.white(` Search: `) + chalk7.white(`"${query}"`) - ); - console.log(); - if (matches.length === 0) { - console.log(chalk7.dim(" No conversations found matching that query.")); - console.log(); - console.log( - chalk7.dim(" Try a shorter term, or use ") + chalk7.cyan("devlog sessions") + chalk7.dim(" to browse all.") - ); - console.log(); - return; - } - const matchWord = matches.length === 1 ? "conversation" : "conversations"; - console.log( - chalk7.dim(` Found ${matches.length} ${matchWord} matching "${query}"`) - ); - console.log(); - const shown = matches.slice(0, 20); - for (let i = 0; i < shown.length; i++) { - const session = shown[i]; - const m = session.meta; - const time = formatSmartTime(session.updatedAt); - const preview = m.firstUserMessage ? truncate(m.firstUserMessage.replace(/\n/g, " ").trim(), 42) : chalk7.dim("(empty)"); - console.log( - chalk7.dim(` ${(i + 1).toString().padEnd(3)} `) + chalk7.white(time.padEnd(16)) + chalk7.cyan(session.projectName.padEnd(14)) + chalk7.white(`"${preview}"`) - ); - const turns = m.humanTurns + m.assistantTurns; - const parts = []; - parts.push(messageCountContext(turns)); - if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD)); - console.log( - chalk7.dim(" ") + " " + " ".repeat(16) + parts.join(chalk7.dim(" \xB7 ")) - ); - console.log(); - } - if (matches.length > 20) { - console.log(chalk7.dim(` + ${matches.length - 20} more matches`)); - console.log(); - } - console.log(chalk7.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk7.dim(" ") + chalk7.cyan("devlog show 1") + chalk7.dim(" view match \xB7 ") + chalk7.cyan(`devlog search "${query} ..."`) + chalk7.dim(" refine") - ); - console.log(); -} - -// src/cli/commands/stats.ts -import chalk8 from "chalk"; -import ora7 from "ora"; -import dayjs5 from "dayjs"; -import isToday3 from "dayjs/plugin/isToday.js"; -dayjs5.extend(isToday3); -function filterByPeriod(sessions, period) { - const now = dayjs5(); - return sessions.filter((s) => { - const d = dayjs5(s.updatedAt); - switch (period) { - case "today": - return d.isToday(); - case "week": - return now.diff(d, "day") < 7; - case "month": - return now.diff(d, "day") < 30; - default: - return true; - } - }); -} -async function statsCommand(options, globalOpts) { - const { config } = ensureInit(); - const period = options.period || "all"; - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora7({ - text: chalk8.dim(" Crunching numbers..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const projects = await discoverProjects(config.claudeDir); - spinner?.stop(); - if (projects.length > 0) { - updateCacheFromStats(computeStats(projects)); - } - const allSessions = []; - for (const p of projects) allSessions.push(...p.sessions); - const filtered = filterByPeriod(allSessions, period); - let totalCost = 0; - let totalTools = 0; - let totalMessages = 0; - const fileSet = /* @__PURE__ */ new Set(); - const toolCounts = /* @__PURE__ */ new Map(); - const projectCounts = /* @__PURE__ */ new Map(); - const costByModel = {}; - for (const s of filtered) { - totalCost += s.meta.totalCostUSD; - totalTools += s.meta.toolCalls; - totalMessages += s.meta.humanTurns + s.meta.assistantTurns; - for (const f of s.meta.filesReferenced) fileSet.add(f); - for (const t of s.meta.uniqueTools) { - toolCounts.set(t, (toolCounts.get(t) || 0) + 1); - } - projectCounts.set( - s.projectName, - (projectCounts.get(s.projectName) || 0) + 1 - ); - for (const [model, cost] of Object.entries(s.meta.costByModel)) { - costByModel[model] = (costByModel[model] || 0) + cost; - } - } - const periodLabel2 = period === "today" ? "Today" : period === "week" ? "This Week" : period === "month" ? "This Month" : "All Time"; - if (isJsonMode()) { - outputJson({ - period: periodLabel2, - sessionCount: filtered.length, - totalMessages, - totalToolCalls: totalTools, - totalFilesTouched: fileSet.size, - totalCostUSD: Math.round(totalCost * 1e6) / 1e6, - topTools: [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([name, count]) => ({ name, count })), - projectBreakdown: [...projectCounts.entries()].sort((a, b) => b[1] - a[1]).map(([name, count]) => ({ name, sessions: count })), - costByModel - }); - return; - } - if (filtered.length === 0) { - console.log(); - console.log( - chalk8.bold.cyan(" \u258C") + chalk8.bold.white(` Stats \u2014 ${periodLabel2}`) - ); - console.log(); - console.log(chalk8.dim(" No sessions in this period.")); - console.log(); - return; - } - console.log(); - console.log( - chalk8.bold.cyan(" \u258C") + chalk8.bold.white(` Stats \u2014 ${periodLabel2}`) - ); - console.log(); - const w = 42; - const line = (label, value) => { - const padding = w - label.length - value.length - 6; - return chalk8.dim(" \u2502 ") + chalk8.white(label) + " ".repeat(Math.max(1, padding)) + chalk8.cyan.bold(value) + chalk8.dim(" \u2502"); - }; - console.log(chalk8.dim(" \u250C" + "\u2500".repeat(w) + "\u2510")); - console.log(line("Sessions", formatNumber(filtered.length))); - console.log(line("Messages", formatNumber(totalMessages))); - console.log(line("Commands run", formatNumber(totalTools))); - console.log(line("Files touched", formatNumber(fileSet.size))); - if (totalCost > 0) { - const costStr = totalCost < 1 ? `$${totalCost.toFixed(3)}` : `$${totalCost.toFixed(2)}`; - console.log(line("Total cost", costStr)); - } - console.log(chalk8.dim(" \u2514" + "\u2500".repeat(w) + "\u2518")); - console.log(); - const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5); - if (topTools.length > 0) { - console.log(chalk8.white(" Most used tools:")); - for (const [name, count] of topTools) { - console.log( - chalk8.dim(" ") + chalk8.green(name.padEnd(16)) + chalk8.dim(`used in ${count} session${count === 1 ? "" : "s"}`) - ); - } - console.log(); - } - const topProjects = [...projectCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3); - if (topProjects.length > 0) { - console.log(chalk8.white(" Most active projects:")); - for (const [name, count] of topProjects) { - const sessionWord = count === 1 ? "session" : "sessions"; - console.log( - chalk8.dim(" ") + chalk8.cyan(name.padEnd(16)) + chalk8.dim(`${count} ${sessionWord}`) - ); - } - console.log(); - } - if (totalCost > 0) { - console.log( - chalk8.dim(" Total cost: ") + costWithContext(totalCost) - ); - console.log(); - } - console.log(chalk8.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk8.dim(" ") + chalk8.cyan("devlog cost") + chalk8.dim(" cost breakdown \xB7 ") + chalk8.cyan("devlog stats --period week") + chalk8.dim(" filter") - ); - console.log(); -} - -// src/cli/commands/cost.ts -import chalk9 from "chalk"; -import ora8 from "ora"; - -// src/core/cost-tracker.ts -import { readdir as readdir2 } from "fs/promises"; -import { createReadStream as createReadStream2 } from "fs"; -import { createInterface as createInterface2 } from "readline"; -import { basename, join as join5 } from "path"; -import { homedir as homedir2 } from "os"; -import dayjs6 from "dayjs"; -var EMPTY_TOTALS = { - usageEvents: 0, - inputTokens: 0, - cachedInputTokens: 0, - outputTokens: 0, - reasoningOutputTokens: 0, - totalTokens: 0, - apiCostUSD: 0, - subscriptionCredits: 0 -}; -var CODEX_API_PRICING_USD = { - "gpt-5.1-codex": { input: 1.25, cachedInput: 0.125, output: 10 }, - "gpt-5.1-codex-max": { input: 1.25, cachedInput: 0.125, output: 10 }, - "gpt-5-codex": { input: 1.25, cachedInput: 0.125, output: 10 } -}; -var CODEX_CREDIT_RATES = { - "gpt-5.5": { input: 125, cachedInput: 12.5, output: 750 }, - "gpt-5.4-mini": { input: 18.75, cachedInput: 1.875, output: 113 }, - "gpt-5.4": { input: 62.5, cachedInput: 6.25, output: 375 }, - "gpt-5.3-codex": { input: 43.75, cachedInput: 4.375, output: 350 }, - "gpt-5.2": { input: 43.75, cachedInput: 4.375, output: 350 }, - "gpt-5.1-codex": { input: 43.75, cachedInput: 4.375, output: 350 }, - "gpt-5-codex": { input: 43.75, cachedInput: 4.375, output: 350 } -}; -function getCodexSessionsDir() { - return join5(homedir2(), ".codex", "sessions"); -} -function getCodexArchivedSessionsDir() { - return join5(homedir2(), ".codex", "archived_sessions"); -} -function emptyCostTotals() { - return { ...EMPTY_TOTALS }; -} -function addCostTotals(target, source) { - const tokens = "tokens" in source ? source.tokens : source; - target.usageEvents += "usageEvents" in source ? source.usageEvents : 1; - target.inputTokens += tokens.inputTokens; - target.cachedInputTokens += tokens.cachedInputTokens; - target.outputTokens += tokens.outputTokens; - target.reasoningOutputTokens += tokens.reasoningOutputTokens; - target.totalTokens += tokens.totalTokens; - target.apiCostUSD += source.apiCostUSD; - target.subscriptionCredits += source.subscriptionCredits; -} -function computeCodexApiCostUSD(model, tokens) { - const rate = findRate(model, CODEX_API_PRICING_USD); - return pricedTotal(tokens, rate); -} -function computeCodexSubscriptionCredits(model, tokens) { - const rate = findRate(model, CODEX_CREDIT_RATES); - return pricedTotal(tokens, rate); -} -async function buildCostReport(options = {}) { - const now = options.now ?? /* @__PURE__ */ new Date(); - const claudeProjectsDir = options.claudeProjectsDir; - const codexSessionsDir = options.codexSessionsDir ?? getCodexSessionsDir(); - const records = []; - const claudeProjects = await discoverProjects(claudeProjectsDir); - for (const project of claudeProjects) { - for (const session of project.sessions) { - records.push(claudeSessionToRecord(session)); - } - } - const codexFiles = await listCodexSessionFiles(codexSessionsDir, codexSessionsDir === getCodexSessionsDir()); - const quota = []; - for (const filePath of codexFiles) { - const parsed = await scanCodexSession(filePath); - records.push(...parsed.records); - quota.push(...parsed.quota); - } - return aggregateCostReport(records, quota, { - now, - claudeProjectsDir: claudeProjectsDir ?? join5(homedir2(), ".claude", "projects"), - codexSessionsDir - }); -} -function aggregateCostReport(records, quota, options) { - const todayStart = dayjs6(options.now).startOf("day"); - const weekStart = dayjs6(options.now).subtract(7, "day").startOf("day"); - const totals = { - today: emptyCostTotals(), - week: emptyCostTotals(), - allTime: emptyCostTotals() - }; - const providers = /* @__PURE__ */ new Map(); - const projects = /* @__PURE__ */ new Map(); - for (const record of records) { - const isToday4 = dayjs6(record.timestamp).isAfter(todayStart) || dayjs6(record.timestamp).isSame(todayStart); - const isWeek = dayjs6(record.timestamp).isAfter(weekStart) || dayjs6(record.timestamp).isSame(weekStart); - addCostTotals(totals.allTime, record); - if (isToday4) addCostTotals(totals.today, record); - if (isWeek) addCostTotals(totals.week, record); - const provider = getProviderSummary(providers, record.provider); - if (!provider.billingModes.includes(record.billingMode)) provider.billingModes.push(record.billingMode); - addCostTotals(provider.allTime, record); - if (isToday4) addCostTotals(provider.today, record); - if (isWeek) addCostTotals(provider.week, record); - const project = getProjectSummary(projects, record.projectName, record.projectPath); - if (!project.providers.includes(record.provider)) project.providers.push(record.provider); - addCostTotals(project.allTime, record); - if (isToday4) addCostTotals(project.today, record); - if (isWeek) addCostTotals(project.week, record); - } - for (const provider of providers.values()) { - provider.quota = latestQuotaForProvider(quota, provider.provider); - } - return { - generatedAt: options.now.toISOString(), - totals: roundReportTotals(totals), - providers: [...providers.values()].sort((a, b) => b.allTime.apiCostUSD - a.allTime.apiCostUSD), - projects: [...projects.values()].sort((a, b) => b.allTime.apiCostUSD - a.allTime.apiCostUSD), - quota: latestQuotaForProvider(quota, "codex"), - sources: { - claudeProjectsDir: options.claudeProjectsDir, - codexSessionsDir: options.codexSessionsDir - } - }; -} -async function scanCodexSession(filePath) { - const records = []; - const quota = []; - const sessionId = basename(filePath, ".jsonl"); - let currentProjectPath = "unknown"; - let currentProjectName = "unknown"; - let currentModel = "gpt-5-codex"; - let previous = emptyTokens(); - const rl = createInterface2({ - input: createReadStream2(filePath, { encoding: "utf-8" }), - crlfDelay: Infinity - }); - for await (const line of rl) { - if (!line.trim()) continue; - let event; - try { - event = JSON.parse(line); - } catch { - continue; - } - const timestamp = event.timestamp ? new Date(event.timestamp) : /* @__PURE__ */ new Date(0); - if (event.type === "turn_context" && event.payload) { - if (typeof event.payload.cwd === "string") { - currentProjectPath = event.payload.cwd; - currentProjectName = basename(currentProjectPath); - } - if (typeof event.payload.model === "string") { - currentModel = event.payload.model; - } - continue; - } - if (event.type !== "event_msg" || event.payload?.type !== "token_count") continue; - quota.push(...extractCodexQuota(event.payload.rate_limits, timestamp)); - const usage = event.payload.info?.total_token_usage; - if (!usage) continue; - const current = normalizeCodexTokens(usage); - const delta = diffTokens(current, previous); - previous = maxTokens(previous, current); - if (delta.totalTokens <= 0) continue; - records.push({ - provider: "codex", - billingMode: "oauth_subscription", - timestamp, - sessionId, - projectName: currentProjectName, - projectPath: currentProjectPath, - model: currentModel, - tokens: delta, - apiCostUSD: computeCodexApiCostUSD(currentModel, delta), - subscriptionCredits: computeCodexSubscriptionCredits(currentModel, delta) - }); - } - return { records, quota }; -} -async function listCodexSessionFiles(root, includeArchived) { - const out = []; - async function walk(dir) { - let entries; - try { - entries = await readdir2(dir, { withFileTypes: true }); - } catch { - return; - } - for (const entry of entries) { - const path2 = join5(dir, entry.name); - if (entry.isDirectory()) await walk(path2); - else if (entry.isFile() && entry.name.endsWith(".jsonl")) out.push(path2); - } - } - await walk(root); - if (includeArchived) await walk(getCodexArchivedSessionsDir()); - return out; -} -function claudeSessionToRecord(session) { - return { - provider: "claude_code", - billingMode: "api", - timestamp: session.updatedAt, - sessionId: session.id, - projectName: session.projectName, - projectPath: session.projectPath, - model: session.meta.models[0] ?? "unknown", - tokens: emptyTokens(), - apiCostUSD: session.meta.totalCostUSD, - subscriptionCredits: 0 - }; -} -function extractCodexQuota(rateLimits, timestamp) { - const windows = []; - for (const name of ["primary", "secondary"]) { - const value = rateLimits?.[name]; - if (!value || typeof value.used_percent !== "number" || typeof value.window_minutes !== "number") continue; - windows.push({ - provider: "codex", - name, - observedAt: timestamp.toISOString(), - usedPercent: clampPercent(value.used_percent), - remainingPercent: clampPercent(100 - value.used_percent), - windowMinutes: value.window_minutes, - resetsAt: typeof value.resets_at === "number" ? new Date(value.resets_at * 1e3).toISOString() : null, - source: "local_log" - }); - } - return windows.sort((a, b) => timestamp.getTime() - timestamp.getTime() || a.name.localeCompare(b.name)); -} -function getProviderSummary(map, provider) { - const existing = map.get(provider); - if (existing) return existing; - const created = { - provider, - billingModes: [], - today: emptyCostTotals(), - week: emptyCostTotals(), - allTime: emptyCostTotals(), - quota: [] - }; - map.set(provider, created); - return created; -} -function getProjectSummary(map, name, path2) { - const key = `${name}\0${path2}`; - const existing = map.get(key); - if (existing) return existing; - const created = { - projectName: name, - projectPath: path2, - providers: [], - today: emptyCostTotals(), - week: emptyCostTotals(), - allTime: emptyCostTotals() - }; - map.set(key, created); - return created; -} -function latestQuotaForProvider(quota, provider) { - const byName = /* @__PURE__ */ new Map(); - for (const item of quota.filter((q) => q.provider === provider)) { - const existing = byName.get(item.name); - if (!existing || new Date(item.observedAt).getTime() >= new Date(existing.observedAt).getTime()) { - byName.set(item.name, item); - } - } - return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)); -} -function roundReportTotals(value) { - value.today = roundTotals(value.today); - value.week = roundTotals(value.week); - value.allTime = roundTotals(value.allTime); - return value; -} -function roundTotals(totals) { - return { - ...totals, - apiCostUSD: roundMoney(totals.apiCostUSD), - subscriptionCredits: roundMoney(totals.subscriptionCredits) - }; -} -function normalizeCodexTokens(usage) { - return { - inputTokens: usage.input_tokens ?? 0, - cachedInputTokens: usage.cached_input_tokens ?? 0, - outputTokens: usage.output_tokens ?? 0, - reasoningOutputTokens: usage.reasoning_output_tokens ?? 0, - totalTokens: usage.total_tokens ?? 0 - }; -} -function emptyTokens() { - return { - inputTokens: 0, - cachedInputTokens: 0, - outputTokens: 0, - reasoningOutputTokens: 0, - totalTokens: 0 - }; -} -function diffTokens(current, previous) { - return { - inputTokens: Math.max(0, current.inputTokens - previous.inputTokens), - cachedInputTokens: Math.max(0, current.cachedInputTokens - previous.cachedInputTokens), - outputTokens: Math.max(0, current.outputTokens - previous.outputTokens), - reasoningOutputTokens: Math.max(0, current.reasoningOutputTokens - previous.reasoningOutputTokens), - totalTokens: Math.max(0, current.totalTokens - previous.totalTokens) - }; -} -function maxTokens(a, b) { - return { - inputTokens: Math.max(a.inputTokens, b.inputTokens), - cachedInputTokens: Math.max(a.cachedInputTokens, b.cachedInputTokens), - outputTokens: Math.max(a.outputTokens, b.outputTokens), - reasoningOutputTokens: Math.max(a.reasoningOutputTokens, b.reasoningOutputTokens), - totalTokens: Math.max(a.totalTokens, b.totalTokens) - }; -} -function findRate(model, table) { - const normalized = model.toLowerCase(); - for (const [key, rate] of Object.entries(table).sort((a, b) => b[0].length - a[0].length)) { - if (normalized.includes(key)) return rate; - } - return table["gpt-5-codex"] ?? table["gpt-5.1-codex"]; -} -function pricedTotal(tokens, rate) { - const perM = 1e6; - return tokens.inputTokens * rate.input / perM + tokens.cachedInputTokens * rate.cachedInput / perM + tokens.outputTokens * rate.output / perM; -} -function clampPercent(value) { - return Math.min(100, Math.max(0, value)); -} -function roundMoney(value) { - return Math.round(value * 1e6) / 1e6; -} - -// src/cli/commands/cost.ts -function normalizePeriod(period) { - switch (period) { - case "today": - return "today"; - case "week": - return "week"; - default: - return "allTime"; - } -} -function periodLabel(period) { - if (period === "today") return "Today"; - if (period === "week") return "This Week"; - return "All Time"; -} -function renderBar(fraction, width = 16) { - const filled = Math.round(Math.max(0, Math.min(1, fraction)) * width); - return chalk9.green("\u2588".repeat(filled)) + chalk9.dim("\u2591".repeat(width - filled)); -} -function formatUsd(value) { - if (value <= 0) return "$0.000"; - return value < 1 ? `$${value.toFixed(3)}` : `$${value.toFixed(2)}`; -} -function formatCredits(value) { - if (value <= 0) return "0 credits"; - return `${value < 10 ? value.toFixed(2) : value.toFixed(1)} credits`; -} -async function costCommand(options, _globalOpts) { - const period = normalizePeriod(options.period); - let spinner = null; - if (!isJsonMode() && !isQuietMode()) { - spinner = ora8({ - text: chalk9.dim(" Calculating costs..."), - spinner: "dots", - color: "cyan", - stream: process.stderr - }).start(); - } - const report = await buildCostReport(); - spinner?.stop(); - if (isJsonMode()) { - outputJson(report); - return; - } - renderReport(report, period); -} -function renderReport(report, period) { - const total = report.totals[period]; - console.log(); - console.log( - chalk9.bold.cyan(" \u258C") + chalk9.bold.white(` Cost Breakdown \u2014 ${periodLabel(period)}`) - ); - console.log(); - if (total.apiCostUSD === 0 && total.subscriptionCredits === 0) { - console.log(chalk9.dim(" No costs recorded in this period.")); - console.log(); - return; - } - console.log(chalk9.dim(" API estimate: ") + costWithContext(total.apiCostUSD)); - if (total.subscriptionCredits > 0) { - console.log(chalk9.dim(" Subscription usage: ") + chalk9.yellow(formatCredits(total.subscriptionCredits))); - } - console.log(chalk9.dim(" Tokens: ") + chalk9.white(total.totalTokens.toLocaleString())); - console.log(); - renderQuota(report); - renderProviders(report, period, total); - renderProjects(report, period, total); - console.log(chalk9.dim(" " + "\u2500".repeat(60))); - console.log(); - console.log( - chalk9.dim(" ") + chalk9.cyan("devlog cost --json") + chalk9.dim(" full report \xB7 ") + chalk9.cyan("devlog cost --period week") + chalk9.dim(" weekly view") - ); - console.log(); -} -function renderQuota(report) { - if (report.quota.length === 0) return; - console.log(chalk9.white(" Quota:")); - for (const q of report.quota) { - const label = q.name === "primary" ? "daily/window" : "weekly"; - const reset = q.resetsAt ? ` resets ${new Date(q.resetsAt).toLocaleString()}` : ""; - console.log( - chalk9.dim(" ") + chalk9.cyan(label.padEnd(14)) + chalk9.yellow(`${q.usedPercent.toFixed(1)}% used`.padEnd(14)) + chalk9.dim(`${q.remainingPercent.toFixed(1)}% left`) + chalk9.dim(reset) - ); - } - console.log(); -} -function renderProviders(report, period, total) { - console.log(chalk9.white(" By provider:")); - for (const provider of report.providers) { - const p = provider[period]; - if (p.apiCostUSD === 0 && p.subscriptionCredits === 0) continue; - const pct = total.apiCostUSD > 0 ? p.apiCostUSD / total.apiCostUSD : 0; - const label = provider.provider === "claude_code" ? "Claude Code" : "Codex"; - console.log( - chalk9.dim(" ") + chalk9.cyan(label.padEnd(18)) + chalk9.yellow(formatUsd(p.apiCostUSD).padEnd(10)) + chalk9.dim(formatCredits(p.subscriptionCredits).padEnd(15)) + renderBar(pct) - ); - } - console.log(); -} -function renderProjects(report, period, total) { - console.log(chalk9.white(" By project:")); - for (const project of report.projects.slice(0, 12)) { - const p = project[period]; - if (p.apiCostUSD === 0 && p.subscriptionCredits === 0) continue; - const pct = total.apiCostUSD > 0 ? p.apiCostUSD / total.apiCostUSD : 0; - const name = project.projectName.length > 24 ? `${project.projectName.slice(0, 23)}\u2026` : project.projectName; - console.log( - chalk9.dim(" ") + chalk9.cyan(name.padEnd(25)) + chalk9.yellow(formatUsd(p.apiCostUSD).padEnd(10)) + chalk9.dim(formatCredits(p.subscriptionCredits).padEnd(15)) + renderBar(pct) - ); - } - console.log(); -} - -// src/cli/commands/statusline.ts -import { readFileSync as readFileSync3 } from "fs"; -import { join as join7 } from "path"; -import { homedir as homedir3 } from "os"; - -// src/core/fast-discovery.ts -import { readdir as readdir3, stat as stat3 } from "fs/promises"; -import { join as join6 } from "path"; -import dayjs7 from "dayjs"; -async function discoverTodayStats(claudeDir) { - const todayMidnight = dayjs7().startOf("day").valueOf(); - const result = { - sessions: 0, - costUSD: 0, - messages: 0, - toolCalls: 0, - filesTouched: 0, - projects: [] - }; - const fileSet = /* @__PURE__ */ new Set(); - const projectSet = /* @__PURE__ */ new Set(); - let entries; - try { - entries = await readdir3(claudeDir, { withFileTypes: true }); - } catch { - return result; - } - for (const entry of entries) { - if (!entry.isDirectory()) continue; - const projectDir = join6(claudeDir, entry.name); - const decodedPath = decodePath(entry.name); - const projectName = getProjectName(decodedPath); - let files; - try { - files = await readdir3(projectDir, { withFileTypes: true }); - } catch { - continue; - } - for (const file of files) { - if (!file.isFile() || !file.name.endsWith(".jsonl")) continue; - const filePath = join6(projectDir, file.name); - try { - const fileStat = await stat3(filePath); - if (fileStat.mtimeMs < todayMidnight) continue; - const meta = await scanSession(filePath); - const lastActivity = meta.lastActivity.getTime(); - if (lastActivity < todayMidnight) continue; - result.sessions++; - result.costUSD += meta.totalCostUSD; - result.messages += meta.messageCount; - result.toolCalls += meta.toolCalls; - for (const f of meta.filesReferenced) fileSet.add(f); - projectSet.add(projectName); - } catch { - continue; - } - } - } - result.filesTouched = fileSet.size; - result.projects = [...projectSet]; - return result; -} - -// src/cli/commands/statusline.ts -import dayjs8 from "dayjs"; -async function statuslineCommand(options) { - const { config } = ensureInit(); - const useCache = options.cache !== false; - const stdinData = process.stdin.isTTY ? null : await readStdinWithTimeout(50); - let cache = useCache ? readStatsCache() : null; - if (cache && useCache && isCacheFresh(cache)) { - process.stdout.write(formatStatusLine(cache, stdinData)); - return; - } - try { - const todayStats = await discoverTodayStats(config.claudeDir); - const now = dayjs8(); - cache = { - timestamp: now.toISOString(), - todayDate: now.format("YYYY-MM-DD"), - today: todayStats, - allTime: cache?.allTime ?? { sessions: 0, costUSD: 0, projects: 0 } - }; - writeStatsCache(cache); - } catch { - if (!cache) { - process.stdout.write("DevLog: scanning..."); - return; - } - } - process.stdout.write(formatStatusLine(cache, stdinData)); -} -async function readStdinWithTimeout(ms) { - return Promise.race([ - new Promise((resolve) => { - let data = ""; - process.stdin.setEncoding("utf-8"); - process.stdin.on("data", (chunk) => { - data += chunk; - }); - process.stdin.on("end", () => { - try { - resolve(JSON.parse(data)); - } catch { - resolve(null); - } - }); - process.stdin.resume(); - }), - new Promise((resolve) => setTimeout(() => resolve(null), ms)) - ]); -} -function readAgentState() { - const statusFile = join7(homedir3(), ".claude-status"); - try { - const raw = readFileSync3(statusFile, "utf-8"); - const match = raw.match(/"state":"([^"]+)"/); - const tsMatch = raw.match(/"ts":(\d+)/); - if (!match) return "idle"; - if (tsMatch) { - const age = Math.floor(Date.now() / 1e3) - Number(tsMatch[1]); - if (age > 30) return "idle"; - } - return match[1]; - } catch { - return "idle"; - } -} -function stateIndicator(state) { - switch (state) { - case "running": - return "\u26A1"; - // ⚡ - case "done": - return "\u2713"; - // ✓ - case "error": - return "\u2717"; - // ✗ - default: - return "\u25CB"; - } -} -function formatStatusLine(cache, stdinData) { - const parts = []; - const state = readAgentState(); - parts.push(stateIndicator(state)); - if (stdinData?.context_window?.used_percentage != null) { - parts.push(`ctx ${stdinData.context_window.used_percentage}%`); - } - if (cache.today.sessions > 0) { - const sessionWord = cache.today.sessions === 1 ? "session" : "sessions"; - parts.push(`\u3010${formatCost(cache.today.costUSD)}\u3011today \xB7 ${cache.today.sessions} ${sessionWord}`); - } else { - parts.push("No sessions today"); - } - if (cache.allTime.costUSD > 0) { - parts.push(`${formatCost(cache.allTime.costUSD)} total`); - } - return parts.join(" \xB7 "); -} -function formatCost(usd) { - if (usd < 0.01) return `$${usd.toFixed(3)}`; - if (usd < 1) return `$${usd.toFixed(2)}`; - if (usd >= 1e3) return `$${usd.toLocaleString("en-US", { maximumFractionDigits: 0 })}`; - return `$${usd.toFixed(2)}`; -} - -// src/cli/commands/setup-statusline.ts -import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, copyFileSync, chmodSync } from "fs"; -import { join as join8, dirname as dirname2 } from "path"; -import { homedir as homedir4 } from "os"; -import { execFileSync } from "child_process"; -import { fileURLToPath } from "url"; -import chalk10 from "chalk"; -function makeHookCommand(state) { - return `bash -c 'echo "{\\"state\\":\\"${state}\\",\\"ts\\":$(date +%s)}" > ~/.claude-status.tmp && mv ~/.claude-status.tmp ~/.claude-status'`; -} -function generateTmuxScript(devlogBin) { - return `#!/usr/bin/env bash -set -euo pipefail -STATUS_FILE="$HOME/.claude-status" -STALE_THRESHOLD=30 -DEVLOG_BIN="${devlogBin}" - -state="idle" -if [[ -f "$STATUS_FILE" ]]; then - raw=$(cat "$STATUS_FILE" 2>/dev/null || echo '{}') - state=$(echo "$raw" | grep -o '"state":"[^"]*"' | head -1 | cut -d'"' -f4) - ts=$(echo "$raw" | grep -o '"ts":[0-9]*' | head -1 | cut -d: -f2) - state="\${state:-idle}" - if [[ -n "$ts" ]]; then - now=$(date +%s) - age=$(( now - ts )) - if (( age > STALE_THRESHOLD )); then - state="idle" - fi - fi -fi - -cost_line=$("$DEVLOG_BIN" statusline < /dev/null 2>/dev/null || echo "") - -cost_color="colour82" -if [[ "$cost_line" =~ \\$([0-9,]+\\.?[0-9]*) ]]; then - amount="\${BASH_REMATCH[1]//,/}" - cents=$(echo "$amount" | awk '{printf "%d", $1 * 100}') - if (( cents >= 1000 )); then - cost_color="colour196" - elif (( cents >= 100 )); then - cost_color="colour226" - fi -fi - -case "$state" in - running) indicator="#[fg=colour82,bold]\u26A1#[default]" ;; - done) indicator="#[fg=colour65]\u2713#[default]" ;; - error) indicator="#[fg=colour196]\u2717#[default]" ;; - *) indicator="#[fg=colour243]\u25CB#[default]" ;; -esac - -if [[ -n "$cost_line" ]]; then - echo "#[fg=\${cost_color}]\${cost_line}#[default] \${indicator}" -else - echo "\${indicator}" -fi -`; -} -var TMUX_COMMENT = "# DevLog status bar"; -async function setupStatuslineCommand() { - const { config } = ensureInit(); - let devlogBin = "devlog"; - try { - devlogBin = execFileSync("which", ["devlog"], { encoding: "utf-8" }).trim(); - } catch { - } - const claudeSettingsPath = join8(homedir4(), ".claude", "settings.json"); - let settings = {}; - if (existsSync5(claudeSettingsPath)) { - try { - settings = JSON.parse(readFileSync4(claudeSettingsPath, "utf-8")); - } catch { - settings = {}; - } - } - settings.statusLine = { - type: "command", - command: `${devlogBin} statusline` - }; - const hooks = settings.hooks ?? {}; - for (const [event, state] of [["PreToolUse", "running"], ["PostToolUse", "done"], ["Stop", "idle"]]) { - const existing = Array.isArray(hooks[event]) ? hooks[event] : []; - const filtered = existing.filter((h) => !h.command?.includes(".claude-status")); - filtered.push({ type: "command", command: makeHookCommand(state) }); - hooks[event] = filtered; - } - settings.hooks = hooks; - mkdirSync3(dirname2(claudeSettingsPath), { recursive: true }); - writeFileSync3(claudeSettingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8"); - console.log(); - console.log(chalk10.green(" \u2713") + chalk10.bold.white(" Claude Code status line + hooks configured")); - const binDir = join8(homedir4(), ".devlog", "bin"); - const scriptDest = join8(binDir, "tmux-claude-status.sh"); - mkdirSync3(binDir, { recursive: true }); - const thisFile = fileURLToPath(import.meta.url); - const scriptSrc = join8(dirname2(thisFile), "..", "..", "scripts", "tmux-claude-status.sh"); - if (existsSync5(scriptSrc)) { - copyFileSync(scriptSrc, scriptDest); - } else { - writeFileSync3(scriptDest, generateTmuxScript(devlogBin), "utf-8"); - } - chmodSync(scriptDest, 493); - console.log(chalk10.green(" \u2713") + chalk10.bold.white(" tmux status script installed")); - const tmuxConfPath = join8(homedir4(), ".tmux.conf"); - let tmuxConf = ""; - if (existsSync5(tmuxConfPath)) { - tmuxConf = readFileSync4(tmuxConfPath, "utf-8"); - } - if (!tmuxConf.includes("tmux-claude-status.sh")) { - const snippet = [ - "", - TMUX_COMMENT, - "set -g status-interval 1", - `set -g status-right '#(${scriptDest})'`, - "" - ].join("\n"); - writeFileSync3(tmuxConfPath, tmuxConf + snippet, "utf-8"); - console.log(chalk10.green(" \u2713") + chalk10.bold.white(" tmux.conf configured")); - try { - execFileSync("tmux", ["source-file", tmuxConfPath], { stdio: "ignore" }); - console.log(chalk10.green(" \u2713") + chalk10.bold.white(" tmux reloaded")); - } catch { - } - } else { - console.log(chalk10.dim(" \u2713 tmux.conf already configured")); - } - console.log(); - console.log(chalk10.dim(" Warming cache...")); - try { - const projects = await discoverProjects(config.claudeDir); - if (projects.length > 0) { - updateCacheFromStats(computeStats(projects)); - } - console.log(chalk10.dim(" Cache ready.")); - } catch { - console.log(chalk10.dim(" Cache will be built on first use.")); - } - console.log(); - console.log(chalk10.white(" Restart Claude Code to see status bar data.")); - console.log(chalk10.white(" tmux users: cost data with color highlights in status bar.")); - console.log(); -} - -// src/cli/commands/setup-tmux.ts -import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, copyFileSync as copyFileSync2, chmodSync as chmodSync2 } from "fs"; -import { join as join9, dirname as dirname3 } from "path"; -import { homedir as homedir5 } from "os"; -import { execFileSync as execFileSync2 } from "child_process"; -import { fileURLToPath as fileURLToPath2 } from "url"; -import chalk11 from "chalk"; -function makeHookCommand2(state) { - return `bash -c 'echo "{\\"state\\":\\"${state}\\",\\"ts\\":$(date +%s)}" > ~/.claude-status.tmp && mv ~/.claude-status.tmp ~/.claude-status'`; -} -function removeExistingDevlogHooks(hooks) { - return hooks.filter((h) => !h.command.includes(".claude-status")); -} -function generateTmuxScript2(devlogBin) { - return `#!/usr/bin/env bash -# tmux-claude-status.sh \u2014 called by tmux status-right every 1s -# Reads agent state from ~/.claude-status and cost from devlog statusline - -set -euo pipefail - -STATUS_FILE="$HOME/.claude-status" -STALE_THRESHOLD=30 # seconds \u2014 treat as idle if older -DEVLOG_BIN="${devlogBin}" - -# \u2500\u2500 Read agent state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -state="idle" -if [[ -f "$STATUS_FILE" ]]; then - raw=$(cat "$STATUS_FILE" 2>/dev/null || echo '{}') - state=$(echo "$raw" | grep -o '"state":"[^"]*"' | head -1 | cut -d'"' -f4) - ts=$(echo "$raw" | grep -o '"ts":[0-9]*' | head -1 | cut -d: -f2) - state="\${state:-idle}" - - # Stale check: if timestamp is older than threshold, force idle - if [[ -n "$ts" ]]; then - now=$(date +%s) - age=$(( now - ts )) - if (( age > STALE_THRESHOLD )); then - state="idle" - fi - fi -fi - -# \u2500\u2500 Read cost data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -cost_line=$("$DEVLOG_BIN" statusline < /dev/null 2>/dev/null || echo "") - -# \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -# Cost color tiers: extract dollar amount for coloring -cost_color="colour82" # green default -if [[ "$cost_line" =~ \\$([0-9,]+\\.?[0-9]*) ]]; then - amount="\${BASH_REMATCH[1]//,/}" - # Compare as integer cents to avoid bash float issues - cents=$(echo "$amount" | awk '{printf "%d", $1 * 100}') - if (( cents >= 1000 )); then - cost_color="colour196" # red: >$10 - elif (( cents >= 100 )); then - cost_color="colour226" # yellow: $1-10 - fi -fi - -# State indicator -case "$state" in - running) indicator="#[fg=colour82,bold]\u26A1#[default]" ;; - done) indicator="#[fg=colour65]\u2713#[default]" ;; - error) indicator="#[fg=colour196]\u2717#[default]" ;; - *) indicator="#[fg=colour243]\u25CB#[default]" ;; -esac - -# Final output -if [[ -n "$cost_line" ]]; then - echo "#[fg=\${cost_color}]\${cost_line}#[default] \${indicator}" -else - echo "\${indicator}" -fi -`; -} -async function setupTmuxCommand() { - let devlogBin = "devlog"; - try { - devlogBin = execFileSync2("which", ["devlog"], { encoding: "utf-8" }).trim(); - } catch { - } - const claudeSettingsPath = join9(homedir5(), ".claude", "settings.json"); - let settings = {}; - if (existsSync6(claudeSettingsPath)) { - try { - settings = JSON.parse(readFileSync5(claudeSettingsPath, "utf-8")); - } catch { - settings = {}; - } - } - if (!settings.hooks) { - settings.hooks = {}; - } - const preToolUse = removeExistingDevlogHooks(settings.hooks.PreToolUse ?? []); - preToolUse.push({ type: "command", command: makeHookCommand2("running") }); - settings.hooks.PreToolUse = preToolUse; - const postToolUse = removeExistingDevlogHooks(settings.hooks.PostToolUse ?? []); - postToolUse.push({ type: "command", command: makeHookCommand2("done") }); - settings.hooks.PostToolUse = postToolUse; - const stop = removeExistingDevlogHooks(settings.hooks.Stop ?? []); - stop.push({ type: "command", command: makeHookCommand2("idle") }); - settings.hooks.Stop = stop; - mkdirSync4(dirname3(claudeSettingsPath), { recursive: true }); - writeFileSync4(claudeSettingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8"); - console.log(); - console.log(chalk11.green(" \u2713") + chalk11.bold.white(" Claude Code hooks installed")); - const destDir = join9(homedir5(), ".devlog", "bin"); - const destPath = join9(destDir, "tmux-claude-status.sh"); - mkdirSync4(destDir, { recursive: true }); - const thisFile = fileURLToPath2(import.meta.url); - const srcPath = join9(dirname3(thisFile), "..", "..", "scripts", "tmux-claude-status.sh"); - if (existsSync6(srcPath)) { - copyFileSync2(srcPath, destPath); - } else { - writeFileSync4(destPath, generateTmuxScript2(devlogBin), "utf-8"); - } - chmodSync2(destPath, 493); - console.log(chalk11.green(" \u2713") + chalk11.bold.white(` tmux script installed to ${destPath}`)); - console.log(); - console.log(chalk11.bold.white(" Add this to your ~/.tmux.conf:")); - console.log(); - console.log(chalk11.cyan(" set -g status-interval 1")); - console.log(chalk11.cyan(" set -g status-right '#(~/.devlog/bin/tmux-claude-status.sh)'")); - console.log(); - console.log(chalk11.bold.white(" Then reload tmux:")); - console.log(); - console.log(chalk11.cyan(" tmux source-file ~/.tmux.conf")); - console.log(); -} - -// src/cli/commands/serve.ts -import { execFile } from "child_process"; -import path from "path"; -import chalk12 from "chalk"; -async function serveCommand(options, globalOpts) { - const port = options.port ?? "3333"; - const projectRoot = path.resolve(import.meta.dirname, "..", "..", ".."); - const nextConfigPath = path.join(projectRoot, "next.config.ts"); - const fs = await import("fs"); - if (!fs.existsSync(nextConfigPath)) { - console.error(chalk12.red("\n Dashboard requires running from the DevLog source repo.")); - console.error(chalk12.dim(" Clone https://github.com/moose-lab/DevLog and run from there.\n")); - process.exit(1); - } - console.log(); - console.log(chalk12.bold.cyan(" \u258C") + chalk12.bold.white(" DevLog Dashboard")); - console.log(chalk12.dim(` Starting on port ${port}...`)); - console.log(); - const child = execFile( - "npx", - ["next", "dev", "--port", port], - { cwd: projectRoot, stdio: "inherit" } - ); - const cleanup = () => { - child.kill("SIGTERM"); - process.exit(0); - }; - process.on("SIGINT", cleanup); - process.on("SIGTERM", cleanup); - await new Promise((resolve, reject) => { - child.on("exit", (code) => { - if (code === 0 || code === null) resolve(); - else reject(new Error(`Dashboard exited with code ${code}`)); - }); - child.on("error", reject); - }); -} - -// src/cli/cli.ts -var VERSION2 = "0.4.0"; -var HELP_TEXT = ` -${chalk13.bold.cyan(" \u258C")} ${chalk13.bold.white("DevLog")} ${chalk13.dim(`v${VERSION2}`)} -${chalk13.dim(" Your Claude Code work journal")} - -${chalk13.bold.white(" Quick Start:")} -${chalk13.dim(" Just run")} ${chalk13.cyan("devlog")} ${chalk13.dim("\u2014 that's it. No setup needed.")} - -${chalk13.bold.white(" Examples:")} -${chalk13.cyan(" devlog")}${chalk13.dim(" See your dashboard")} -${chalk13.cyan(" devlog today")}${chalk13.dim(" What did I do today?")} -${chalk13.cyan(" devlog sessions")}${chalk13.dim(" Browse all sessions by project")} -${chalk13.cyan(" devlog sessions -p chatbot")}${chalk13.dim(" Filter to a specific project")} -${chalk13.cyan(" devlog show 1")}${chalk13.dim(" View your most recent conversation")} -${chalk13.cyan(" devlog show 1 --summary")}${chalk13.dim(" Quick narrative summary")} -${chalk13.cyan(" devlog show abc123")}${chalk13.dim(" View a specific session by ID")} -${chalk13.cyan(' devlog search "auth bug"')}${chalk13.dim(" Find a conversation")} -${chalk13.cyan(" devlog stats")}${chalk13.dim(" Usage trends")} -${chalk13.cyan(" devlog cost")}${chalk13.dim(" Cost breakdown")} - -${chalk13.bold.white(" Dashboard:")} -${chalk13.cyan(" devlog serve")}${chalk13.dim(" Start the web dashboard")} -${chalk13.cyan(" devlog serve -p 4000")}${chalk13.dim(" Dashboard on custom port")} - -${chalk13.bold.white(" Agent Integration:")} -${chalk13.cyan(" devlog setup-statusline")}${chalk13.dim(" Configure Claude Code status bar")} -${chalk13.cyan(" devlog setup-tmux")}${chalk13.dim(" Configure tmux cost dashboard")} -${chalk13.cyan(" devlog statusline")}${chalk13.dim(" Output status line (used by Claude Code)")} - -${chalk13.bold.white(" Output Modes:")} -${chalk13.cyan(" devlog --json")}${chalk13.dim(" JSON output for scripts/agents")} -${chalk13.cyan(" devlog -q")}${chalk13.dim(" Quiet mode (no spinners/banners)")} -${chalk13.cyan(" devlog --no-color")}${chalk13.dim(" Plain text, no ANSI escapes")} -`; -var program = new Command(); -var KNOWN_COMMANDS = [ - "serve", - "init", - "sessions", - "show", - "today", - "search", - "stats", - "cost", - "statusline", - "setup-statusline", - "setup-tmux" -]; -function getGlobalOpts() { - const opts = program.opts(); - return { json: !!opts.json, quiet: !!opts.quiet }; -} -function handleError(err, globalOpts) { - const message = err instanceof Error ? err.message : String(err); - if (globalOpts.json) { - outputJson({ error: message }); - } else { - console.error( - chalk13.red("\n Error:"), - message - ); - } - process.exit(1); -} -program.name("devlog").description("Your Claude Code work journal \u2014 auto-generated dev logs").version(VERSION2).option("--json", "Output as JSON for scripts and agents").option("-q, --quiet", "Suppress non-essential output").option("--no-color", "Disable colored output").addHelpText("before", HELP_TEXT); -program.hook("preAction", () => { - const opts = program.opts(); - if (opts.color === false) { - process.env.NO_COLOR = "1"; - } - initOutput({ json: !!opts.json, quiet: !!opts.quiet }); -}); -program.action(async () => { - const globalOpts = getGlobalOpts(); - try { - await dashboardCommand(globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("serve").description("Start the DevLog dashboard").option("-p, --port ", "Port number", "3333").action(async (options) => { - const globalOpts = getGlobalOpts(); - try { - await serveCommand(options, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("init").description("Set up DevLog (usually auto-detected, you rarely need this)").action(async () => { - const globalOpts = getGlobalOpts(); - try { - await initCommand(globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("sessions").description("Browse all sessions grouped by project").option("-p, --project ", "Filter by project name (fuzzy match)").option("-n, --limit ", "Max sessions to display", "30").option("-a, --all", "Show all sessions").action(async (options) => { - const globalOpts = getGlobalOpts(); - try { - await sessionsCommand(options, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("show ").description("View a full conversation (use a number like 1, 2, 3 or a session ID)").option("-n, --limit ", "Max events to display", "50").option("-s, --summary", "Show a narrative summary instead of the full conversation").action(async (sessionRef, options) => { - const globalOpts = getGlobalOpts(); - try { - await showCommand(sessionRef, options, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("today").description("What did I do today?").action(async () => { - const globalOpts = getGlobalOpts(); - try { - await todayCommand(globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("search ").description("Search sessions by message, project, or tool name").action(async (query) => { - const globalOpts = getGlobalOpts(); - try { - await searchCommand(query, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("stats").description("Aggregated usage statistics").option("--period ", "Filter: today, week, month, all", "all").action(async (options) => { - const globalOpts = getGlobalOpts(); - try { - await statsCommand(options, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("cost").description("Cost, credits, and quota breakdown").option("--period ", "Filter: today, week, all", "all").action(async (options) => { - const globalOpts = getGlobalOpts(); - try { - await costCommand(options, globalOpts); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("statusline").description("Output status line for Claude Code integration").option("--no-cache", "Force refresh, skip cache").action(async (options) => { - try { - await statuslineCommand(options); - } catch { - } -}); -program.command("setup-statusline").description("Configure Claude Code status bar integration").action(async () => { - const globalOpts = getGlobalOpts(); - try { - await setupStatuslineCommand(); - } catch (err) { - handleError(err, globalOpts); - } -}); -program.command("setup-tmux").description("Configure tmux status bar with cost dashboard").action(async () => { - const globalOpts = getGlobalOpts(); - try { - await setupTmuxCommand(); - } catch (err) { - handleError(err, globalOpts); - } -}); -var userArgs = process.argv.slice(2).filter((a) => !a.startsWith("-")); -if (userArgs.length === 1 && !KNOWN_COMMANDS.includes(userArgs[0])) { - const candidate = userArgs[0]; - const isNumber = /^\d+$/.test(candidate); - const isSessionId = /^[0-9a-f]{6,}$/i.test(candidate); - if (!isNumber && !isSessionId) { - let suggestion = ""; - let bestDist = Infinity; - for (const cmd of KNOWN_COMMANDS) { - const dist = levenshtein(candidate, cmd); - if (dist < bestDist) { - bestDist = dist; - suggestion = cmd; - } - } - if (bestDist <= 3) { - console.error(); - console.error( - chalk13.yellow(` Unknown command: ${candidate}`) - ); - console.error( - chalk13.dim(" Did you mean: ") + chalk13.cyan(suggestion) + chalk13.dim("?") - ); - console.error( - chalk13.dim(" Run ") + chalk13.cyan("devlog --help") + chalk13.dim(" to see all commands.") - ); - console.error(); - process.exit(1); - } - } -} -program.parse(); -//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/dist/cli.js.map b/dist/cli.js.map deleted file mode 100644 index 18f4eca..0000000 --- a/dist/cli.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../src/cli/cli.ts","../src/cli/commands/dashboard.ts","../src/core/config.ts","../src/core/paths.ts","../src/core/discovery.ts","../src/core/parser.ts","../src/core/pricing.ts","../src/cli/utils/format.ts","../src/cli/utils/output.ts","../src/cli/commands/shared.ts","../src/core/cache.ts","../src/cli/commands/init.ts","../src/cli/commands/sessions.ts","../src/cli/commands/show.ts","../src/cli/commands/today.ts","../src/cli/commands/search.ts","../src/cli/commands/stats.ts","../src/cli/commands/cost.ts","../src/core/cost-tracker.ts","../src/cli/commands/statusline.ts","../src/core/fast-discovery.ts","../src/cli/commands/setup-statusline.ts","../src/cli/commands/setup-tmux.ts","../src/cli/commands/serve.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { dashboardCommand } from \"./commands/dashboard\";\nimport { initCommand } from \"./commands/init\";\nimport { sessionsCommand } from \"./commands/sessions\";\nimport { showCommand } from \"./commands/show\";\nimport { todayCommand } from \"./commands/today\";\nimport { searchCommand } from \"./commands/search\";\nimport { statsCommand } from \"./commands/stats\";\nimport { costCommand } from \"./commands/cost\";\nimport { statuslineCommand } from \"./commands/statusline\";\nimport { setupStatuslineCommand } from \"./commands/setup-statusline\";\nimport { setupTmuxCommand } from \"./commands/setup-tmux\";\nimport { serveCommand } from \"./commands/serve\";\nimport { initOutput, outputJson } from \"./utils/output\";\nimport { levenshtein } from \"./utils/format\";\nimport type { GlobalOptions } from \"../core/types\";\n\nconst VERSION = \"0.4.0\";\n\nconst HELP_TEXT = `\n${chalk.bold.cyan(\" ▌\")} ${chalk.bold.white(\"DevLog\")} ${chalk.dim(`v${VERSION}`)}\n${chalk.dim(\" Your Claude Code work journal\")}\n\n${chalk.bold.white(\" Quick Start:\")}\n${chalk.dim(\" Just run\")} ${chalk.cyan(\"devlog\")} ${chalk.dim(\"— that's it. No setup needed.\")}\n\n${chalk.bold.white(\" Examples:\")}\n${chalk.cyan(\" devlog\")}${chalk.dim(\" See your dashboard\")}\n${chalk.cyan(\" devlog today\")}${chalk.dim(\" What did I do today?\")}\n${chalk.cyan(\" devlog sessions\")}${chalk.dim(\" Browse all sessions by project\")}\n${chalk.cyan(\" devlog sessions -p chatbot\")}${chalk.dim(\" Filter to a specific project\")}\n${chalk.cyan(\" devlog show 1\")}${chalk.dim(\" View your most recent conversation\")}\n${chalk.cyan(\" devlog show 1 --summary\")}${chalk.dim(\" Quick narrative summary\")}\n${chalk.cyan(\" devlog show abc123\")}${chalk.dim(\" View a specific session by ID\")}\n${chalk.cyan(\" devlog search \\\"auth bug\\\"\")}${chalk.dim(\" Find a conversation\")}\n${chalk.cyan(\" devlog stats\")}${chalk.dim(\" Usage trends\")}\n${chalk.cyan(\" devlog cost\")}${chalk.dim(\" Cost breakdown\")}\n\n${chalk.bold.white(\" Dashboard:\")}\n${chalk.cyan(\" devlog serve\")}${chalk.dim(\" Start the web dashboard\")}\n${chalk.cyan(\" devlog serve -p 4000\")}${chalk.dim(\" Dashboard on custom port\")}\n\n${chalk.bold.white(\" Agent Integration:\")}\n${chalk.cyan(\" devlog setup-statusline\")}${chalk.dim(\" Configure Claude Code status bar\")}\n${chalk.cyan(\" devlog setup-tmux\")}${chalk.dim(\" Configure tmux cost dashboard\")}\n${chalk.cyan(\" devlog statusline\")}${chalk.dim(\" Output status line (used by Claude Code)\")}\n\n${chalk.bold.white(\" Output Modes:\")}\n${chalk.cyan(\" devlog --json\")}${chalk.dim(\" JSON output for scripts/agents\")}\n${chalk.cyan(\" devlog -q\")}${chalk.dim(\" Quiet mode (no spinners/banners)\")}\n${chalk.cyan(\" devlog --no-color\")}${chalk.dim(\" Plain text, no ANSI escapes\")}\n`;\n\nconst program = new Command();\n\nconst KNOWN_COMMANDS = [\n \"serve\",\n \"init\",\n \"sessions\",\n \"show\",\n \"today\",\n \"search\",\n \"stats\",\n \"cost\",\n \"statusline\",\n \"setup-statusline\",\n \"setup-tmux\",\n];\n\nfunction getGlobalOpts(): GlobalOptions {\n const opts = program.opts();\n return { json: !!opts.json, quiet: !!opts.quiet };\n}\n\nfunction handleError(err: unknown, globalOpts: GlobalOptions): never {\n const message = err instanceof Error ? err.message : String(err);\n if (globalOpts.json) {\n outputJson({ error: message });\n } else {\n console.error(\n chalk.red(\"\\n Error:\"),\n message\n );\n }\n process.exit(1);\n}\n\nprogram\n .name(\"devlog\")\n .description(\"Your Claude Code work journal — auto-generated dev logs\")\n .version(VERSION)\n .option(\"--json\", \"Output as JSON for scripts and agents\")\n .option(\"-q, --quiet\", \"Suppress non-essential output\")\n .option(\"--no-color\", \"Disable colored output\")\n .addHelpText(\"before\", HELP_TEXT);\n\n// Initialize output context before every command\nprogram.hook(\"preAction\", () => {\n const opts = program.opts();\n if (opts.color === false) {\n process.env.NO_COLOR = \"1\";\n }\n initOutput({ json: !!opts.json, quiet: !!opts.quiet });\n});\n\n// ── Default: `devlog` with no args → dashboard ──────────\nprogram.action(async () => {\n const globalOpts = getGlobalOpts();\n try {\n await dashboardCommand(globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n});\n\n// ── devlog serve ─────────────────────────────────────────\nprogram\n .command(\"serve\")\n .description(\"Start the DevLog dashboard\")\n .option(\"-p, --port \", \"Port number\", \"3333\")\n .action(async (options) => {\n const globalOpts = getGlobalOpts();\n try {\n await serveCommand(options, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog init ──────────────────────────────────────────\nprogram\n .command(\"init\")\n .description(\"Set up DevLog (usually auto-detected, you rarely need this)\")\n .action(async () => {\n const globalOpts = getGlobalOpts();\n try {\n await initCommand(globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog sessions ──────────────────────────────────────\nprogram\n .command(\"sessions\")\n .description(\"Browse all sessions grouped by project\")\n .option(\"-p, --project \", \"Filter by project name (fuzzy match)\")\n .option(\"-n, --limit \", \"Max sessions to display\", \"30\")\n .option(\"-a, --all\", \"Show all sessions\")\n .action(async (options) => {\n const globalOpts = getGlobalOpts();\n try {\n await sessionsCommand(options, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog show ────────────────────────────────\nprogram\n .command(\"show \")\n .description(\"View a full conversation (use a number like 1, 2, 3 or a session ID)\")\n .option(\"-n, --limit \", \"Max events to display\", \"50\")\n .option(\"-s, --summary\", \"Show a narrative summary instead of the full conversation\")\n .action(async (sessionRef: string, options) => {\n const globalOpts = getGlobalOpts();\n try {\n await showCommand(sessionRef, options, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog today ─────────────────────────────────────────\nprogram\n .command(\"today\")\n .description(\"What did I do today?\")\n .action(async () => {\n const globalOpts = getGlobalOpts();\n try {\n await todayCommand(globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog search ────────────────────────────────\nprogram\n .command(\"search \")\n .description(\"Search sessions by message, project, or tool name\")\n .action(async (query: string) => {\n const globalOpts = getGlobalOpts();\n try {\n await searchCommand(query, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog stats ─────────────────────────────────────────\nprogram\n .command(\"stats\")\n .description(\"Aggregated usage statistics\")\n .option(\"--period \", \"Filter: today, week, month, all\", \"all\")\n .action(async (options) => {\n const globalOpts = getGlobalOpts();\n try {\n await statsCommand(options, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog cost ──────────────────────────────────────────\nprogram\n .command(\"cost\")\n .description(\"Cost, credits, and quota breakdown\")\n .option(\"--period \", \"Filter: today, week, all\", \"all\")\n .action(async (options) => {\n const globalOpts = getGlobalOpts();\n try {\n await costCommand(options, globalOpts);\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog statusline ───────────────────────────────────\nprogram\n .command(\"statusline\")\n .description(\"Output status line for Claude Code integration\")\n .option(\"--no-cache\", \"Force refresh, skip cache\")\n .action(async (options) => {\n try {\n await statuslineCommand(options);\n } catch {\n // Silent failure — status line must never crash\n }\n });\n\n// ── devlog setup-statusline ─────────────────────────────\nprogram\n .command(\"setup-statusline\")\n .description(\"Configure Claude Code status bar integration\")\n .action(async () => {\n const globalOpts = getGlobalOpts();\n try {\n await setupStatuslineCommand();\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── devlog setup-tmux ───────────────────────────────────\nprogram\n .command(\"setup-tmux\")\n .description(\"Configure tmux status bar with cost dashboard\")\n .action(async () => {\n const globalOpts = getGlobalOpts();\n try {\n await setupTmuxCommand();\n } catch (err) {\n handleError(err, globalOpts);\n }\n });\n\n// ── \"Did you mean?\" for unknown commands (Principle 3) ───\n// Commander treats unknown words as args to default command.\n// We intercept by checking process.argv before parse.\nconst userArgs = process.argv.slice(2).filter((a) => !a.startsWith(\"-\"));\nif (userArgs.length === 1 && !KNOWN_COMMANDS.includes(userArgs[0])) {\n // Check if it looks like a mistyped command (not a session ID or number)\n const candidate = userArgs[0];\n const isNumber = /^\\d+$/.test(candidate);\n const isSessionId = /^[0-9a-f]{6,}$/i.test(candidate);\n\n if (!isNumber && !isSessionId) {\n let suggestion = \"\";\n let bestDist = Infinity;\n\n for (const cmd of KNOWN_COMMANDS) {\n const dist = levenshtein(candidate, cmd);\n if (dist < bestDist) {\n bestDist = dist;\n suggestion = cmd;\n }\n }\n\n if (bestDist <= 3) {\n console.error();\n console.error(\n chalk.yellow(` Unknown command: ${candidate}`)\n );\n console.error(\n chalk.dim(\" Did you mean: \") + chalk.cyan(suggestion) + chalk.dim(\"?\")\n );\n console.error(\n chalk.dim(\" Run \") +\n chalk.cyan(\"devlog --help\") +\n chalk.dim(\" to see all commands.\")\n );\n console.error();\n process.exit(1);\n }\n }\n}\n\nprogram.parse();\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { existsSync } from \"fs\";\nimport { ensureInit } from \"../../core/config.js\";\nimport {\n discoverProjects,\n computeStats,\n groupSessionsByTime,\n} from \"../../core/discovery.js\";\nimport type { Session, AggregateStats, GlobalOptions, DashboardJson } from \"../../core/types.js\";\nimport {\n formatSmartTime,\n formatNumber,\n truncate,\n costWithContext,\n messageCountContext,\n toolCountContext,\n fileCountContext,\n} from \"../utils/format.js\";\nimport { getClaudeProjectsDir } from \"../../core/paths.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\nimport { toSessionJson } from \"./shared\";\nimport { updateCacheFromStats } from \"../../core/cache.js\";\n\nconst VERSION = \"0.4.0\";\n\n/**\n * The default command. This IS the product.\n * Run `devlog` → see your world with Claude.\n */\nexport async function dashboardCommand(globalOpts: GlobalOptions): Promise {\n const { config, isFirstRun } = ensureInit();\n\n // ── No Claude Code installed ──────────────────────\n if (!existsSync(config.claudeDir)) {\n if (isJsonMode()) {\n outputJson({ error: \"Claude Code not found\", path: getClaudeProjectsDir() });\n process.exit(1);\n }\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" DevLog\")\n );\n console.log();\n console.log(\n chalk.white(\" Hmm, I can't find Claude Code on this machine.\")\n );\n console.log(\n chalk.dim(\" I looked for: \") + chalk.white(getClaudeProjectsDir())\n );\n console.log();\n console.log(\n chalk.white(\" To get started:\")\n );\n console.log(\n chalk.dim(\" 1. Install Claude Code → \") + chalk.cyan(\"https://claude.ai/code\")\n );\n console.log(\n chalk.dim(\" 2. Have a conversation with Claude in any project\")\n );\n console.log(\n chalk.dim(\" 3. Come back and run \") + chalk.cyan(\"devlog\") + chalk.dim(\" again\")\n );\n console.log();\n return;\n }\n\n // ── Scan ──────────────────────────────────────────\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Reading your Claude Code history...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir, (msg) => {\n if (spinner) spinner.text = chalk.dim(` ${msg}`);\n });\n\n spinner?.stop();\n\n // ── No sessions yet ───────────────────────────────\n if (projects.length === 0) {\n if (isJsonMode()) {\n outputJson({ version: VERSION, timestamp: new Date().toISOString(), summary: \"No sessions found\", stats: { totalProjects: 0, totalSessions: 0, totalToolCalls: 0, totalFilesTouched: 0, totalCostUSD: 0, todaySessions: 0, todayCostUSD: 0 }, recentSessions: [] });\n return;\n }\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" DevLog\")\n );\n console.log();\n console.log(\n chalk.white(\" No conversations found yet.\")\n );\n console.log(\n chalk.dim(\" Start a Claude Code session in any project, then come back!\")\n );\n console.log();\n return;\n }\n\n const stats = computeStats(projects);\n updateCacheFromStats(stats);\n const groups = groupSessionsByTime(projects);\n\n // ── JSON output ────────────────────────────────────\n if (isJsonMode()) {\n const allSessions = projects.flatMap((p) => p.sessions);\n allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n const recent = allSessions.slice(0, 10);\n\n const projectWord = stats.totalProjects === 1 ? \"project\" : \"projects\";\n const sessionWord = stats.totalSessions === 1 ? \"conversation\" : \"conversations\";\n\n const data: DashboardJson = {\n version: VERSION,\n timestamp: new Date().toISOString(),\n summary: `You and Claude had ${stats.totalSessions} ${sessionWord} across ${stats.totalProjects} ${projectWord}`,\n stats: {\n totalProjects: stats.totalProjects,\n totalSessions: stats.totalSessions,\n totalToolCalls: stats.totalToolCalls,\n totalFilesTouched: stats.allFilesReferenced.length,\n totalCostUSD: Math.round(stats.totalCostUSD * 1000000) / 1000000,\n todaySessions: stats.todaySessions,\n todayCostUSD: Math.round(stats.todayCostUSD * 1000000) / 1000000,\n },\n recentSessions: recent.map(toSessionJson),\n };\n outputJson(data);\n return;\n }\n\n // ── Render ────────────────────────────────────────\n console.log();\n\n if (!isQuietMode()) {\n if (isFirstRun) {\n renderWelcome(stats);\n } else {\n renderBanner();\n }\n }\n\n renderNarrativeStats(stats);\n renderSessionGroups(groups, stats);\n\n if (!isQuietMode()) {\n renderNextSteps(stats, isFirstRun);\n }\n}\n\n// ─────────────────────────────────────────────────────\n// Render helpers\n// ─────────────────────────────────────────────────────\n\nfunction renderWelcome(stats: AggregateStats): void {\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" Welcome to DevLog!\")\n );\n console.log();\n console.log(\n chalk.white(\" I found your Claude Code history — let me show you what\") +\n chalk.white(\" you've been building.\")\n );\n console.log();\n}\n\nfunction renderBanner(): void {\n console.log(\n chalk.bold.cyan(\" ▌\") +\n chalk.bold.white(\" DevLog\")\n );\n console.log();\n}\n\nfunction renderNarrativeStats(stats: AggregateStats): void {\n const projectWord = stats.totalProjects === 1 ? \"project\" : \"projects\";\n const sessionWord = stats.totalSessions === 1 ? \"conversation\" : \"conversations\";\n\n console.log(\n chalk.dim(\" \") +\n chalk.white(\"You and Claude had \") +\n chalk.cyan.bold(String(stats.totalSessions)) +\n chalk.white(` ${sessionWord} across `) +\n chalk.cyan.bold(String(stats.totalProjects)) +\n chalk.white(` ${projectWord}.`)\n );\n\n const activityParts: string[] = [];\n\n if (stats.totalToolCalls > 0) {\n activityParts.push(\n chalk.white(\"Claude ran \") +\n chalk.green.bold(formatNumber(stats.totalToolCalls)) +\n chalk.white(\" commands\")\n );\n }\n\n if (stats.allFilesReferenced.length > 0) {\n activityParts.push(\n chalk.white(\"touched \") +\n chalk.blue.bold(String(stats.allFilesReferenced.length)) +\n chalk.white(\" files\")\n );\n }\n\n if (activityParts.length > 0) {\n console.log(chalk.dim(\" \") + activityParts.join(chalk.dim(\" and \")));\n }\n\n if (stats.totalCostUSD > 0) {\n const costStr = stats.totalCostUSD < 1\n ? `$${stats.totalCostUSD.toFixed(3)}`\n : `$${stats.totalCostUSD.toFixed(2)}`;\n\n let costContext = \"\";\n if (stats.totalCostUSD < 0.10) costContext = \" — less than a cup of coffee\";\n else if (stats.totalCostUSD < 1) costContext = \" — pretty efficient\";\n else if (stats.totalCostUSD < 5) costContext = \" — solid investment\";\n\n console.log(\n chalk.dim(\" \") +\n chalk.white(\"Total cost: \") +\n chalk.yellow.bold(costStr) +\n chalk.dim(costContext)\n );\n }\n\n if (stats.todaySessions > 0) {\n const todayWord = stats.todaySessions === 1 ? \"session\" : \"sessions\";\n console.log(\n chalk.dim(\" \") +\n chalk.green(\"▸ \") +\n chalk.white.bold(`${stats.todaySessions} ${todayWord} today`) +\n (stats.todayCostUSD > 0\n ? chalk.dim(` · $${stats.todayCostUSD.toFixed(3)}`)\n : \"\")\n );\n }\n\n console.log();\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n}\n\nfunction renderSessionGroups(\n groups: {\n today: Session[];\n yesterday: Session[];\n thisWeek: Session[];\n older: Session[];\n },\n stats: AggregateStats\n): void {\n const hasToday = groups.today.length > 0;\n const hasYesterday = groups.yesterday.length > 0;\n const hasThisWeek = groups.thisWeek.length > 0;\n const hasOlder = groups.older.length > 0;\n\n if (hasToday) {\n renderGroup(\"Today\", groups.today, chalk.green);\n }\n\n if (hasYesterday) {\n renderGroup(\"Yesterday\", groups.yesterday, chalk.blue);\n }\n\n if (hasThisWeek) {\n renderGroup(\"This Week\", groups.thisWeek, chalk.white);\n }\n\n if (hasOlder) {\n const count = groups.older.length;\n console.log(\n chalk.dim(` + ${count} older session${count === 1 ? \"\" : \"s\"}`)\n );\n console.log();\n }\n\n if (!hasToday && !hasYesterday && !hasThisWeek && !hasOlder) {\n console.log(chalk.dim(\" No sessions found.\"));\n console.log();\n }\n}\n\nfunction renderGroup(\n label: string,\n sessions: Session[],\n accentColor: typeof chalk\n): void {\n console.log(accentColor.bold(` ${label}`));\n console.log();\n\n for (const session of sessions) {\n renderSessionCard(session, accentColor);\n }\n}\n\nfunction renderSessionCard(session: Session, accentColor: typeof chalk): void {\n const m = session.meta;\n const time = formatSmartTime(session.updatedAt);\n const preview = m.firstUserMessage\n ? truncate(m.firstUserMessage.replace(/\\n/g, \" \").trim(), 50)\n : chalk.dim(\"(empty session)\");\n\n const timeStr = time.length > 14 ? time.slice(0, 14) : time;\n console.log(\n chalk.dim(\" \") +\n accentColor(timeStr.padEnd(16)) +\n chalk.bold.white(session.projectName.padEnd(14)) +\n chalk.white(preview)\n );\n\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls));\n if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n if (m.errorCount > 0) {\n const errWord = m.errorCount === 1 ? \"error\" : \"errors\";\n parts.push(chalk.red(`${m.errorCount} ${errWord}`));\n }\n\n console.log(\n chalk.dim(\" \") +\n \" \".repeat(30) +\n parts.join(chalk.dim(\" · \"))\n );\n console.log();\n}\n\nfunction renderNextSteps(stats: AggregateStats, isFirstRun: boolean): void {\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n\n if (isFirstRun) {\n console.log(chalk.white(\" What you can do next:\"));\n console.log();\n console.log(\n chalk.cyan(\" devlog today\") +\n chalk.dim(\" What did I do today?\")\n );\n console.log(\n chalk.cyan(\" devlog sessions\") +\n chalk.dim(\" Browse all sessions by project\")\n );\n console.log(\n chalk.cyan(\" devlog show \") +\n chalk.dim(\" View a full conversation\")\n );\n console.log(\n chalk.cyan(\" devlog search \\\"auth\\\"\") +\n chalk.dim(\" Find a conversation\")\n );\n console.log();\n console.log(\n chalk.dim(\" Tip: Just run \") +\n chalk.cyan(\"devlog\") +\n chalk.dim(\" anytime to see this dashboard.\")\n );\n } else {\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog today\") +\n chalk.dim(\" today · \") +\n chalk.cyan(\"devlog sessions\") +\n chalk.dim(\" all · \") +\n chalk.cyan(\"devlog show \") +\n chalk.dim(\" view · \") +\n chalk.cyan(\"devlog search\") +\n chalk.dim(\" find\")\n );\n }\n console.log();\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport toml from \"toml\";\nimport type { DevLogConfig } from \"./types\";\nimport {\n getClaudeProjectsDir,\n getDevlogDir,\n getConfigPath,\n} from \"./paths\";\n\nconst DEFAULT_CONFIG = `# DevLog Configuration\n# Auto-generated by devlog\n\n[paths]\n# Claude Code projects directory\nclaude_dir = \"{{claudeDir}}\"\n\n# DevLog data directory\ndevlog_dir = \"{{devlogDir}}\"\n\n[display]\n# Maximum number of sessions to show in list\nmax_sessions = 50\n\n# Truncate message preview to this length\npreview_length = 80\n`;\n\nexport function isInitialized(): boolean {\n return existsSync(getConfigPath());\n}\n\nexport function initConfig(): DevLogConfig {\n const devlogDir = getDevlogDir();\n const claudeDir = getClaudeProjectsDir();\n const configPath = getConfigPath();\n\n mkdirSync(devlogDir, { recursive: true });\n mkdirSync(join(devlogDir, \"daily\"), { recursive: true });\n mkdirSync(join(devlogDir, \"reports\"), { recursive: true });\n mkdirSync(join(devlogDir, \"db\"), { recursive: true });\n\n const configContent = DEFAULT_CONFIG.replace(\n \"{{claudeDir}}\",\n claudeDir\n ).replace(\"{{devlogDir}}\", devlogDir);\n\n writeFileSync(configPath, configContent, \"utf-8\");\n\n return { claudeDir, devlogDir, version: \"0.1.0\" };\n}\n\n/**\n * Ensure DevLog is initialized. Returns config + whether this was the first run.\n */\nexport function ensureInit(): { config: DevLogConfig; isFirstRun: boolean } {\n if (!isInitialized()) {\n return { config: initConfig(), isFirstRun: true };\n }\n return { config: loadConfig(), isFirstRun: false };\n}\n\nexport function loadConfig(): DevLogConfig {\n const configPath = getConfigPath();\n\n if (!existsSync(configPath)) {\n return {\n claudeDir: getClaudeProjectsDir(),\n devlogDir: getDevlogDir(),\n version: \"0.1.0\",\n };\n }\n\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = toml.parse(raw);\n\n return {\n claudeDir: parsed.paths?.claude_dir || getClaudeProjectsDir(),\n devlogDir: parsed.paths?.devlog_dir || getDevlogDir(),\n version: \"0.1.0\",\n };\n } catch {\n return {\n claudeDir: getClaudeProjectsDir(),\n devlogDir: getDevlogDir(),\n version: \"0.1.0\",\n };\n }\n}\n","import { homedir } from \"os\";\nimport { join } from \"path\";\n\n/**\n * Default Claude Code projects directory\n */\nexport function getClaudeProjectsDir(): string {\n return join(homedir(), \".claude\", \"projects\");\n}\n\n/**\n * Default DevLog data directory\n */\nexport function getDevlogDir(): string {\n return join(homedir(), \".devlog\");\n}\n\n/**\n * Default DevLog config file path\n */\nexport function getConfigPath(): string {\n return join(getDevlogDir(), \"config.toml\");\n}\n\n/**\n * Decode Claude Code's path encoding:\n * -Users-dong-projects-myapp → /Users/dong/projects/myapp\n *\n * Claude Code encodes the project path by replacing '/' with '-'\n * and prepending a '-' to the path.\n */\nexport function decodePath(encoded: string): string {\n // The encoded path starts with the drive/root indicator\n // e.g., \"-Users-dong-xxx\" → \"/Users/dong/xxx\"\n // Handle both macOS and Linux paths\n if (encoded.startsWith(\"-\")) {\n return encoded.replace(/-/g, \"/\");\n }\n return encoded;\n}\n\n/**\n * Get a human-readable project name from the decoded path\n */\nexport function getProjectName(decodedPath: string): string {\n const parts = decodedPath.split(\"/\").filter(Boolean);\n // Return the last meaningful directory name\n return parts[parts.length - 1] || decodedPath;\n}\n","import { readdir, stat } from \"fs/promises\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Project, Session, AggregateStats } from \"./types\";\nimport {\n decodePath,\n getProjectName,\n getClaudeProjectsDir,\n} from \"./paths\";\nimport { scanSession } from \"./parser\";\nimport dayjs from \"dayjs\";\n\n/**\n * Discover all Claude Code projects and sessions with rich metadata.\n * Accepts an optional progress callback for spinner updates.\n */\nexport async function discoverProjects(\n claudeDir?: string,\n onProgress?: (msg: string) => void\n): Promise {\n const projectsDir = claudeDir || getClaudeProjectsDir();\n\n if (!existsSync(projectsDir)) {\n return [];\n }\n\n const entries = await readdir(projectsDir, { withFileTypes: true });\n const projects: Project[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const projectDir = join(projectsDir, entry.name);\n const decodedPath = decodePath(entry.name);\n const projectName = getProjectName(decodedPath);\n\n onProgress?.(`Scanning ${projectName}...`);\n\n const sessions = await discoverSessions(\n projectDir,\n decodedPath,\n projectName\n );\n\n if (sessions.length > 0) {\n projects.push({\n path: decodedPath,\n name: projectName,\n encodedPath: entry.name,\n sessionCount: sessions.length,\n sessions,\n });\n }\n }\n\n // Sort projects by most recent session\n projects.sort((a, b) => {\n const aLatest = Math.max(\n ...a.sessions.map((s) => s.updatedAt.getTime())\n );\n const bLatest = Math.max(\n ...b.sessions.map((s) => s.updatedAt.getTime())\n );\n return bLatest - aLatest;\n });\n\n return projects;\n}\n\nasync function discoverSessions(\n projectDir: string,\n decodedPath: string,\n projectName: string\n): Promise {\n const sessions: Session[] = [];\n\n try {\n const entries = await readdir(projectDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".jsonl\")) continue;\n\n const filePath = join(projectDir, entry.name);\n const sessionId = entry.name.replace(\".jsonl\", \"\");\n\n try {\n const fileStat = await stat(filePath);\n const meta = await scanSession(filePath);\n\n // Use internal timestamps when available (more accurate than fs mtime)\n const createdAt = meta.firstActivity.getTime() > 0 ? meta.firstActivity : fileStat.birthtime;\n const updatedAt = meta.lastActivity.getTime() > 0 ? meta.lastActivity : fileStat.mtime;\n\n sessions.push({\n id: sessionId,\n projectPath: decodedPath,\n projectName,\n filePath,\n createdAt,\n updatedAt,\n meta,\n });\n } catch {\n continue;\n }\n }\n } catch {\n return [];\n }\n\n sessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n return sessions;\n}\n\n/**\n * Compute aggregate stats with today-awareness for the emotional dashboard.\n */\nexport function computeStats(projects: Project[]): AggregateStats {\n const today = dayjs().startOf(\"day\");\n let totalSessions = 0;\n let totalMessages = 0;\n let totalHumanTurns = 0;\n let totalAssistantTurns = 0;\n let totalToolCalls = 0;\n let totalCostUSD = 0;\n let totalDurationMs = 0;\n let todaySessions = 0;\n let todayMessages = 0;\n let todayCostUSD = 0;\n\n const allTools = new Set();\n const allFiles = new Set();\n const allModels = new Set();\n\n let mostActiveProject = \"\";\n let mostActiveProjectSessions = 0;\n\n for (const project of projects) {\n totalSessions += project.sessionCount;\n\n if (project.sessionCount > mostActiveProjectSessions) {\n mostActiveProjectSessions = project.sessionCount;\n mostActiveProject = project.name;\n }\n\n for (const session of project.sessions) {\n const m = session.meta;\n totalMessages += m.messageCount;\n totalHumanTurns += m.humanTurns;\n totalAssistantTurns += m.assistantTurns;\n totalToolCalls += m.toolCalls;\n totalCostUSD += m.totalCostUSD;\n totalDurationMs += m.totalDurationMs;\n\n m.uniqueTools.forEach((t) => allTools.add(t));\n m.filesReferenced.forEach((f) => allFiles.add(f));\n m.models.forEach((model) => allModels.add(model));\n\n // Today tracking\n if (dayjs(session.updatedAt).isAfter(today)) {\n todaySessions++;\n todayMessages += m.messageCount;\n todayCostUSD += m.totalCostUSD;\n }\n }\n }\n\n return {\n totalProjects: projects.length,\n totalSessions,\n totalMessages,\n totalHumanTurns,\n totalAssistantTurns,\n totalToolCalls,\n totalCostUSD,\n totalDurationMs,\n uniqueToolsUsed: [...allTools],\n allFilesReferenced: [...allFiles],\n modelsUsed: [...allModels],\n todaySessions,\n todayMessages,\n todayCostUSD,\n mostActiveProject,\n mostActiveProjectSessions,\n };\n}\n\n/**\n * Group sessions by time period for smart display\n */\nexport function groupSessionsByTime(\n projects: Project[]\n): {\n today: Session[];\n yesterday: Session[];\n thisWeek: Session[];\n older: Session[];\n} {\n const now = dayjs();\n const todayStart = now.startOf(\"day\");\n const yesterdayStart = todayStart.subtract(1, \"day\");\n const weekStart = now.startOf(\"week\");\n\n const groups = {\n today: [] as Session[],\n yesterday: [] as Session[],\n thisWeek: [] as Session[],\n older: [] as Session[],\n };\n\n for (const project of projects) {\n for (const session of project.sessions) {\n const d = dayjs(session.updatedAt);\n if (d.isAfter(todayStart)) {\n groups.today.push(session);\n } else if (d.isAfter(yesterdayStart)) {\n groups.yesterday.push(session);\n } else if (d.isAfter(weekStart)) {\n groups.thisWeek.push(session);\n } else {\n groups.older.push(session);\n }\n }\n }\n\n // Sort each group by most recent first\n for (const group of Object.values(groups)) {\n group.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n }\n\n return groups;\n}\n","import { createReadStream } from \"fs\";\nimport { createInterface } from \"readline\";\nimport type {\n RawJsonlEvent,\n DevLogEvent,\n ContentBlock,\n TextBlock,\n ToolUseBlock,\n ToolResultBlock,\n SessionMeta,\n} from \"./types\";\nimport { computeCost } from \"./pricing\";\n\n// Types to skip entirely\nconst SKIP_TYPES = new Set([\n \"progress\",\n \"file-history-snapshot\",\n \"queue-operation\",\n]);\n\n/**\n * Resolve the effective role from the event.\n * Real Claude Code uses type:\"user\"/\"assistant\", legacy uses type:\"human\"/\"assistant\".\n */\nfunction resolveRole(event: RawJsonlEvent): \"human\" | \"assistant\" | null {\n const t = event.type;\n if (t === \"human\" || t === \"user\") return \"human\";\n if (t === \"assistant\") return \"assistant\";\n return null;\n}\n\n/**\n * Get content blocks from the event, supporting both real and legacy formats.\n * Real: event.message.content\n * Legacy: event.content\n */\nfunction getContent(event: RawJsonlEvent): ContentBlock[] | string | undefined {\n if (event.message && typeof event.message === \"object\" && event.message.content != null) {\n return event.message.content;\n }\n return event.content;\n}\n\n/**\n * Get model from the event, supporting both formats.\n */\nfunction getModel(event: RawJsonlEvent): string | undefined {\n if (event.message && typeof event.message === \"object\" && event.message.model) {\n return event.message.model;\n }\n return event.model;\n}\n\n/**\n * Rich scan: extract full metadata from a session file in a single streaming pass.\n */\nexport async function scanSession(filePath: string): Promise {\n const meta: SessionMeta = {\n messageCount: 0,\n humanTurns: 0,\n assistantTurns: 0,\n toolCalls: 0,\n uniqueTools: [],\n filesReferenced: [],\n totalCostUSD: 0,\n totalDurationMs: 0,\n models: [],\n firstUserMessage: \"\",\n lastActivity: new Date(0),\n firstActivity: new Date(),\n errorCount: 0,\n costByModel: {},\n };\n\n const toolSet = new Set();\n const fileSet = new Set();\n const modelSet = new Set();\n const costedMessageIds = new Set();\n\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n try {\n const event = JSON.parse(line) as RawJsonlEvent;\n\n if (SKIP_TYPES.has(event.type)) continue;\n\n const ts = event.timestamp ? new Date(event.timestamp) : null;\n\n if (ts) {\n if (ts < meta.firstActivity) meta.firstActivity = ts;\n if (ts > meta.lastActivity) meta.lastActivity = ts;\n }\n\n const role = resolveRole(event);\n\n // Count messages\n if (role === \"human\") {\n meta.humanTurns++;\n meta.messageCount++;\n }\n if (role === \"assistant\") {\n meta.assistantTurns++;\n meta.messageCount++;\n }\n\n // First user message\n if (role === \"human\" && !meta.firstUserMessage) {\n meta.firstUserMessage = extractTextContent(event);\n }\n\n // Cost: assistant messages from one model step can appear in multiple\n // JSONL rows with the same message.id. Count that usage once.\n const model = getModel(event);\n const message = event.message && typeof event.message === \"object\" ? event.message : undefined;\n const usage = message?.usage;\n const messageId = typeof message?.id === \"string\" ? message.id : undefined;\n const shouldCountUsage = Boolean(usage) && (!messageId || !costedMessageIds.has(messageId));\n\n if (model && usage && shouldCountUsage) {\n if (messageId) costedMessageIds.add(messageId);\n const cost = computeCost(model, usage);\n meta.totalCostUSD += cost;\n meta.costByModel[model] = (meta.costByModel[model] || 0) + cost;\n } else if (event.costUSD && typeof event.costUSD === \"number\") {\n // Legacy fallback\n meta.totalCostUSD += event.costUSD;\n const m = model || \"unknown\";\n meta.costByModel[m] = (meta.costByModel[m] || 0) + event.costUSD;\n }\n\n // Duration from system turn_duration events\n if (event.type === \"system\" && event.subtype === \"turn_duration\") {\n const dur = (event as Record).durationMs;\n if (typeof dur === \"number\") {\n meta.totalDurationMs += dur;\n }\n }\n if (event.durationMs && typeof event.durationMs === \"number\") {\n meta.totalDurationMs += event.durationMs;\n }\n\n // Model tracking\n if (model) {\n modelSet.add(model);\n }\n\n // Tool call extraction from content blocks\n const content = getContent(event);\n if (Array.isArray(content)) {\n for (const block of content as ContentBlock[]) {\n if (block.type === \"tool_use\") {\n const tb = block as ToolUseBlock;\n meta.toolCalls++;\n toolSet.add(tb.name);\n\n // Extract file references from tool inputs\n const input = tb.input;\n if (input) {\n for (const key of [\"file_path\", \"path\", \"filePath\"]) {\n if (input[key] && typeof input[key] === \"string\") {\n fileSet.add(input[key] as string);\n }\n }\n }\n }\n if (block.type === \"tool_result\") {\n const rb = block as ToolResultBlock;\n if (rb.is_error) meta.errorCount++;\n }\n }\n }\n } catch {\n continue;\n }\n }\n\n meta.uniqueTools = [...toolSet];\n meta.filesReferenced = [...fileSet];\n meta.models = [...modelSet];\n\n return meta;\n}\n\n/**\n * Fully parse a session file into DevLogEvent array.\n */\nexport async function parseSessionFile(\n filePath: string,\n sessionId: string\n): Promise {\n const events: DevLogEvent[] = [];\n let lineIndex = 0;\n\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n lineIndex++;\n\n try {\n const raw = JSON.parse(line) as RawJsonlEvent;\n if (SKIP_TYPES.has(raw.type)) continue;\n const parsed = normalizeEvent(raw, sessionId, lineIndex);\n if (parsed.length > 0) {\n events.push(...parsed);\n }\n } catch {\n continue;\n }\n }\n\n return events;\n}\n\nfunction normalizeEvent(\n raw: RawJsonlEvent,\n sessionId: string,\n lineIndex: number\n): DevLogEvent[] {\n const events: DevLogEvent[] = [];\n const timestamp = raw.timestamp ? new Date(raw.timestamp) : new Date();\n const baseId = raw.uuid || `${sessionId}-${lineIndex}`;\n const role = resolveRole(raw);\n const content = getContent(raw);\n const model = getModel(raw);\n\n if (role && Array.isArray(content)) {\n const blocks = content as ContentBlock[];\n let blockIndex = 0;\n\n for (const block of blocks) {\n blockIndex++;\n const eventId = `${baseId}-${blockIndex}`;\n\n if (block.type === \"text\") {\n const textBlock = block as TextBlock;\n events.push({\n id: eventId,\n sessionId,\n timestamp,\n role: role,\n type: \"text\",\n content: textBlock.text,\n costUSD: raw.costUSD,\n durationMs: raw.durationMs,\n model,\n raw,\n });\n } else if (block.type === \"tool_use\") {\n const toolBlock = block as ToolUseBlock;\n events.push({\n id: eventId,\n sessionId,\n timestamp,\n role: \"tool_use\",\n type: \"tool_use\",\n content: `${toolBlock.name}(${summarizeToolInput(toolBlock.input)})`,\n toolName: toolBlock.name,\n toolInput: toolBlock.input,\n toolUseId: toolBlock.id,\n raw,\n });\n } else if (block.type === \"tool_result\") {\n const resultBlock = block as ToolResultBlock;\n events.push({\n id: eventId,\n sessionId,\n timestamp,\n role: \"tool_result\",\n type: \"tool_result\",\n content: extractToolResultContent(resultBlock),\n toolUseId: resultBlock.tool_use_id,\n isError: resultBlock.is_error,\n raw,\n });\n }\n }\n\n if (typeof content === \"string\") {\n events.push({\n id: baseId,\n sessionId,\n timestamp,\n role: role,\n type: \"message\",\n content: content,\n raw,\n });\n }\n\n if (events.length === 0) {\n events.push({\n id: baseId,\n sessionId,\n timestamp,\n role: role,\n type: \"message\",\n content: extractTextContent(raw),\n raw,\n });\n }\n } else if (role === \"human\" && typeof content === \"string\") {\n events.push({\n id: baseId,\n sessionId,\n timestamp,\n role: \"human\",\n type: \"message\",\n content: content,\n raw,\n });\n } else if (raw.type === \"summary\") {\n events.push({\n id: baseId,\n sessionId,\n timestamp,\n role: \"system\",\n type: \"summary\",\n content: raw.summary || \"\",\n raw,\n });\n }\n\n return events;\n}\n\nfunction extractTextContent(event: RawJsonlEvent): string {\n // Check message.content first (real Claude Code format)\n const msgContent = event.message && typeof event.message === \"object\" ? event.message.content : undefined;\n if (typeof msgContent === \"string\") return msgContent;\n if (Array.isArray(msgContent)) {\n const textBlocks = (msgContent as ContentBlock[]).filter(\n (b): b is TextBlock => b.type === \"text\"\n );\n if (textBlocks.length > 0) return textBlocks.map((b) => b.text).join(\"\\n\");\n }\n\n // Legacy format\n if (typeof event.content === \"string\") return event.content;\n if (Array.isArray(event.content)) {\n const textBlocks = event.content.filter(\n (b): b is TextBlock => b.type === \"text\"\n );\n if (textBlocks.length > 0) return textBlocks.map((b) => b.text).join(\"\\n\");\n }\n return \"\";\n}\n\nfunction summarizeToolInput(input: Record): string {\n const parts: string[] = [];\n if (input.command && typeof input.command === \"string\")\n parts.push(truncateStr(input.command, 60));\n if (input.file_path && typeof input.file_path === \"string\")\n parts.push(input.file_path as string);\n if (input.path && typeof input.path === \"string\")\n parts.push(input.path as string);\n if (input.query && typeof input.query === \"string\")\n parts.push(truncateStr(input.query, 40));\n\n if (parts.length === 0) {\n return Object.keys(input).slice(0, 3).join(\", \");\n }\n return parts.join(\", \");\n}\n\nfunction extractToolResultContent(block: ToolResultBlock): string {\n if (typeof block.content === \"string\") return block.content;\n if (Array.isArray(block.content)) {\n return block.content\n .filter((item) => item.text)\n .map((item) => item.text)\n .join(\"\\n\");\n }\n return \"\";\n}\n\nfunction truncateStr(str: string, max: number): string {\n if (str.length <= max) return str;\n return str.slice(0, max - 1) + \"\\u2026\";\n}\n","import type { TokenUsage } from \"./types\";\n\n// Pricing per million tokens (USD)\nconst PRICING: Record = {\n \"claude-opus-4-7\": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 },\n \"claude-opus-4-6\": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 },\n \"claude-opus-4-5\": { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.5 },\n \"claude-opus-4-1\": { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.5 },\n \"claude-opus-4\": { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.5 },\n \"claude-sonnet-4-6\": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 },\n \"claude-sonnet-4-5-20241022\": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 },\n \"claude-sonnet-4-5\": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 },\n \"claude-sonnet-4\": { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 },\n \"claude-haiku-4-5\": { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.1 },\n \"claude-haiku-3-5\": { input: 0.80, output: 4, cacheCreation: 1, cacheRead: 0.08 },\n \"claude-3-5-haiku\": { input: 0.80, output: 4, cacheCreation: 1, cacheRead: 0.08 },\n};\n\nconst FALLBACK = { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 };\n\nfunction findPricing(model: string) {\n if (PRICING[model]) return PRICING[model];\n // Fuzzy match: check if model string contains a known key\n for (const [key, val] of Object.entries(PRICING).sort((a, b) => b[0].length - a[0].length)) {\n if (model.includes(key) || key.includes(model)) return val;\n }\n // Match by family\n if (model.includes(\"opus\")) return PRICING[\"claude-opus-4-6\"];\n if (model.includes(\"haiku\")) return PRICING[\"claude-haiku-4-5\"];\n if (model.includes(\"sonnet\")) return PRICING[\"claude-sonnet-4-6\"];\n return FALLBACK;\n}\n\nexport function computeCost(model: string, usage: TokenUsage): number {\n const p = findPricing(model);\n const perM = 1_000_000;\n\n let cost = 0;\n cost += (usage.input_tokens || 0) * p.input / perM;\n cost += (usage.output_tokens || 0) * p.output / perM;\n cost += (usage.cache_creation_input_tokens || 0) * p.cacheCreation / perM;\n cost += (usage.cache_read_input_tokens || 0) * p.cacheRead / perM;\n\n return cost;\n}\n","import chalk from \"chalk\";\nimport dayjs from \"dayjs\";\nimport relativeTime from \"dayjs/plugin/relativeTime.js\";\nimport isToday from \"dayjs/plugin/isToday.js\";\nimport isYesterday from \"dayjs/plugin/isYesterday.js\";\n\ndayjs.extend(relativeTime);\ndayjs.extend(isToday);\ndayjs.extend(isYesterday);\n\n/**\n * Smart time formatting:\n * Today: \"2:30 PM\" (just the time)\n * Yesterday: \"Yesterday 2:30 PM\"\n * This week: \"Mon 2:30 PM\"\n * Older: \"Jan 15, 2:30 PM\"\n */\nexport function formatSmartTime(date: Date): string {\n const d = dayjs(date);\n if (d.isToday()) return d.format(\"h:mm A\");\n if (d.isYesterday()) return \"Yest \" + d.format(\"h:mm A\");\n\n const now = dayjs();\n const diffDays = now.diff(d, \"day\");\n if (diffDays < 7) return d.format(\"ddd h:mm A\");\n\n return d.format(\"MMM D, h:mm A\");\n}\n\nexport function formatDate(date: Date): string {\n return dayjs(date).format(\"YYYY-MM-DD HH:mm\");\n}\n\nexport function formatRelative(date: Date): string {\n return dayjs(date).fromNow();\n}\n\nexport function truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 1) + \"…\";\n}\n\n/**\n * Format cost with appropriate precision\n */\nexport function formatCost(usd: number): string {\n if (usd === 0) return chalk.dim(\"—\");\n if (usd < 0.01) return chalk.green(`$${usd.toFixed(4)}`);\n if (usd < 1) return chalk.green(`$${usd.toFixed(3)}`);\n return chalk.yellow(`$${usd.toFixed(2)}`);\n}\n\n/**\n * Format duration in human-readable form\n */\nexport function formatDuration(ms: number): string {\n if (ms === 0) return chalk.dim(\"—\");\n const seconds = Math.round(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n if (minutes < 60) return `${minutes}m ${remainingSeconds}s`;\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n return `${hours}h ${remainingMinutes}m`;\n}\n\nexport function formatRole(role: string): string {\n switch (role) {\n case \"human\":\n return chalk.blue.bold(\"You\");\n case \"assistant\":\n return chalk.gray.bold(\"Claude\");\n case \"tool_use\":\n return chalk.green.bold(\"Tool\");\n case \"tool_result\":\n return chalk.yellow.bold(\"Result\");\n default:\n return chalk.dim(role);\n }\n}\n\nexport function formatNumber(n: number): string {\n return n.toLocaleString();\n}\n\n// ── Styled printing ─────────────────────────────────────\n\nexport function printHeader(title: string): void {\n console.log();\n console.log(chalk.bold.white(title));\n console.log(chalk.dim(\"─\".repeat(Math.min(title.length + 10, 60))));\n}\n\nexport function printSuccess(msg: string): void {\n console.log(chalk.green(\" ✓ \") + msg);\n}\n\nexport function printWarn(msg: string): void {\n console.error(chalk.yellow(\" ⚠ \") + msg);\n}\n\nexport function printError(msg: string): void {\n console.error(chalk.red(\" ✗ \") + msg);\n}\n\nexport function printInfo(msg: string): void {\n console.log(chalk.cyan(\" ℹ \") + msg);\n}\n\n/**\n * Render a compact stat badge: \" label value\"\n */\nexport function statBadge(\n label: string,\n value: string | number,\n color: typeof chalk = chalk\n): string {\n return (\n chalk.dim(\" \") +\n chalk.dim(label + \" \") +\n color(typeof value === \"number\" ? formatNumber(value) : value)\n );\n}\n\n// ── Humanize helpers (Principle 1: 说人话) ──────────────\n\nconst TOOL_NAMES: Record = {\n Bash: \"ran a command\",\n Read: \"read a file\",\n Write: \"wrote a file\",\n Edit: \"edited a file\",\n Glob: \"searched for files\",\n Grep: \"searched code\",\n Agent: \"used an agent\",\n WebSearch: \"searched the web\",\n WebFetch: \"fetched a page\",\n TodoWrite: \"updated todos\",\n TodoRead: \"checked todos\",\n};\n\n/**\n * Map a raw tool name to a human-readable description.\n */\nexport function humanizeToolName(name: string): string {\n if (TOOL_NAMES[name]) return TOOL_NAMES[name];\n // CamelCase → space-separated lowercase\n return name.replace(/([a-z])([A-Z])/g, \"$1 $2\").toLowerCase();\n}\n\nconst TOOL_PLURALS: Record = {\n Bash: { singular: \"ran a command\", plural: \"ran commands\" },\n Read: { singular: \"read a file\", plural: \"read files\" },\n Write: { singular: \"wrote a file\", plural: \"wrote files\" },\n Edit: { singular: \"edited a file\", plural: \"edited files\" },\n Glob: { singular: \"searched for files\", plural: \"searched for files\" },\n Grep: { singular: \"searched code\", plural: \"searched code\" },\n Agent: { singular: \"used an agent\", plural: \"used agents\" },\n};\n\n/**\n * Group tool arrays into a summary like \"read 3 files, ran 2 commands, edited 1 file\".\n */\nexport function humanizeToolSummary(tools: string[]): string {\n const counts = new Map();\n for (const t of tools) {\n counts.set(t, (counts.get(t) || 0) + 1);\n }\n\n const parts: string[] = [];\n for (const [name, count] of counts) {\n const p = TOOL_PLURALS[name];\n if (p) {\n parts.push(count === 1 ? p.singular : `${p.plural}`);\n } else {\n const human = humanizeToolName(name);\n parts.push(count === 1 ? human : `${human} (×${count})`);\n }\n }\n\n if (parts.length === 0) return \"\";\n if (parts.length === 1) return `Claude ${parts[0]}`;\n const last = parts.pop()!;\n return `Claude ${parts.join(\", \")}, and ${last}`;\n}\n\n// ── Context helpers (Principle 5: 数字要有上下文) ────────\n\n/**\n * Cost with context suffix.\n */\nexport function costWithContext(usd: number): string {\n if (usd === 0) return chalk.dim(\"—\");\n\n const formatted =\n usd < 0.01\n ? `$${usd.toFixed(4)}`\n : usd < 1\n ? `$${usd.toFixed(3)}`\n : `$${usd.toFixed(2)}`;\n\n let context = \"\";\n if (usd < 0.01) context = \" — barely a penny\";\n else if (usd < 0.05) context = \" — pocket change\";\n else if (usd < 0.15) context = \" — pretty efficient\";\n else if (usd < 0.50) context = \" — a good session\";\n else if (usd < 1) context = \" — solid investment\";\n else if (usd < 5) context = \" — heavy session\";\n else context = \" — serious work\";\n\n return chalk.yellow(formatted) + chalk.dim(context);\n}\n\n/**\n * Message count with context.\n */\nexport function messageCountContext(turns: number): string {\n if (turns <= 2) return chalk.dim(\"quick question\");\n if (turns <= 4) return chalk.dim(\"quick chat\");\n if (turns <= 10) return chalk.dim(`${turns} messages`);\n if (turns <= 25) return chalk.white(`${turns} messages`) + chalk.dim(\" — solid session\");\n if (turns <= 50) return chalk.white(`${turns} messages`) + chalk.dim(\" — deep dive\");\n return chalk.white(`${turns} messages`) + chalk.dim(\" — marathon\");\n}\n\n/**\n * File count with context.\n */\nexport function fileCountContext(count: number): string {\n if (count === 0) return \"\";\n if (count === 1) return chalk.blue(\"touched 1 file\");\n if (count <= 5) return chalk.blue(`touched ${count} files`);\n if (count <= 15) return chalk.blue(`touched ${count} files`) + chalk.dim(\" — broad changes\");\n return chalk.blue(`touched ${count} files`) + chalk.dim(\" — major refactor\");\n}\n\n/**\n * Tool count with context.\n */\nexport function toolCountContext(count: number): string {\n if (count === 0) return \"\";\n if (count <= 10) return chalk.green(`ran ${count} commands`);\n if (count <= 30) return chalk.green(`ran ${count} commands`) + chalk.dim(\" — busy session\");\n return chalk.green(`ran ${count} commands`) + chalk.dim(\" — heavy automation\");\n}\n\n// ── Fuzzy matching (Principle 3: 永远不卡住) ────────────\n\n/**\n * Simple Levenshtein distance for \"did you mean?\" suggestions.\n */\nexport function levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));\n for (let i = 0; i <= m; i++) dp[i][0] = i;\n for (let j = 0; j <= n; j++) dp[0][j] = j;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] =\n a[i - 1] === b[j - 1]\n ? dp[i - 1][j - 1]\n : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\n }\n }\n return dp[m][n];\n}\n","export interface OutputContext {\n json: boolean;\n quiet: boolean;\n}\n\nlet ctx: OutputContext = { json: false, quiet: false };\n\nexport function initOutput(opts: OutputContext): void {\n ctx = opts;\n}\n\nexport function getOutputContext(): OutputContext {\n return ctx;\n}\n\n/** Write JSON to stdout */\nexport function outputJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\n/** Progress info to stderr (suppressed in quiet mode) */\nexport function logStatus(msg: string): void {\n if (!ctx.quiet) {\n process.stderr.write(msg + \"\\n\");\n }\n}\n\n/** Errors always go to stderr */\nexport function logError(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\n/** Whether we are in JSON output mode */\nexport function isJsonMode(): boolean {\n return ctx.json;\n}\n\n/** Whether we are in quiet mode */\nexport function isQuietMode(): boolean {\n return ctx.quiet;\n}\n","import type { Session, SessionJson } from \"../../core/types.js\";\n\nexport function toSessionJson(session: Session): SessionJson {\n return {\n id: session.id,\n projectName: session.projectName,\n projectPath: session.projectPath,\n createdAt: session.createdAt.toISOString(),\n updatedAt: session.updatedAt.toISOString(),\n messageCount: session.meta.messageCount,\n toolCalls: session.meta.toolCalls,\n filesTouched: session.meta.filesReferenced.length,\n costUSD: Math.round(session.meta.totalCostUSD * 1000000) / 1000000,\n firstMessage: session.meta.firstUserMessage,\n };\n}\n","import { readFileSync, writeFileSync, renameSync, mkdirSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport dayjs from \"dayjs\";\nimport type { StatsCache, AggregateStats } from \"./types\";\nimport { getDevlogDir } from \"./paths\";\n\nconst CACHE_FILENAME = \"stats-cache.json\";\nconst DEFAULT_MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes\n\nfunction getCachePath(): string {\n return join(getDevlogDir(), \"db\", CACHE_FILENAME);\n}\n\nexport function readStatsCache(): StatsCache | null {\n try {\n const raw = readFileSync(getCachePath(), \"utf-8\");\n return JSON.parse(raw) as StatsCache;\n } catch {\n return null;\n }\n}\n\nexport function writeStatsCache(cache: StatsCache): void {\n const cachePath = getCachePath();\n const tmpPath = cachePath + \".tmp\";\n try {\n mkdirSync(dirname(cachePath), { recursive: true });\n writeFileSync(tmpPath, JSON.stringify(cache, null, 2), \"utf-8\");\n renameSync(tmpPath, cachePath);\n } catch {\n // Best-effort — don't crash the command if cache write fails\n }\n}\n\nexport function isCacheFresh(cache: StatsCache, maxAgeMs?: number): boolean {\n const maxAge = maxAgeMs ?? DEFAULT_MAX_AGE_MS;\n const todayStr = dayjs().format(\"YYYY-MM-DD\");\n\n // Invalidate on day change\n if (cache.todayDate !== todayStr) return false;\n\n const age = Date.now() - new Date(cache.timestamp).getTime();\n return age < maxAge;\n}\n\nexport function updateCacheFromStats(stats: AggregateStats): void {\n const now = dayjs();\n const cache: StatsCache = {\n timestamp: now.toISOString(),\n todayDate: now.format(\"YYYY-MM-DD\"),\n today: {\n sessions: stats.todaySessions,\n costUSD: stats.todayCostUSD,\n messages: stats.todayMessages,\n toolCalls: stats.totalToolCalls, // approx — full stats don't split today's tool calls\n filesTouched: stats.allFilesReferenced.length,\n projects: stats.mostActiveProject ? [stats.mostActiveProject] : [],\n },\n allTime: {\n sessions: stats.totalSessions,\n costUSD: stats.totalCostUSD,\n projects: stats.totalProjects,\n },\n };\n writeStatsCache(cache);\n}\n","import { existsSync } from \"fs\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { initConfig, isInitialized, loadConfig } from \"../../core/config.js\";\nimport { getClaudeProjectsDir, getDevlogDir } from \"../../core/paths.js\";\nimport { discoverProjects, computeStats } from \"../../core/discovery.js\";\nimport {\n printSuccess,\n printError,\n formatNumber,\n} from \"../utils/format.js\";\nimport type { GlobalOptions } from \"../../core/types.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\n\nexport async function initCommand(globalOpts: GlobalOptions): Promise {\n if (!isJsonMode()) {\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" DevLog Setup\")\n );\n console.log();\n }\n\n // Already initialized\n if (isInitialized()) {\n const config = loadConfig();\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n printSuccess(\"DevLog is already set up\");\n console.log(\n chalk.dim(\" Config: \") + chalk.white(getDevlogDir() + \"/config.toml\")\n );\n console.log(\n chalk.dim(\" Claude: \") + chalk.white(config.claudeDir)\n );\n console.log();\n\n spinner = ora({\n text: chalk.dim(\" Checking your sessions...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n const stats = computeStats(projects);\n spinner?.stop();\n\n if (isJsonMode()) {\n outputJson({ status: \"already_initialized\", configPath: getDevlogDir() + \"/config.toml\", stats: { totalProjects: stats.totalProjects, totalSessions: stats.totalSessions, totalMessages: stats.totalMessages } });\n return;\n }\n\n renderStatsBox(stats);\n\n console.log(\n chalk.dim(\" Everything looks good! Run \") +\n chalk.cyan(\"devlog\") +\n chalk.dim(\" to see your dashboard.\")\n );\n console.log();\n return;\n }\n\n // Check Claude Code\n const claudeDir = getClaudeProjectsDir();\n\n if (!existsSync(claudeDir)) {\n if (isJsonMode()) {\n outputJson({ error: \"Claude Code not found\", path: claudeDir });\n process.exit(1);\n }\n printError(\"Claude Code not found\");\n console.log();\n console.log(\n chalk.white(\" I looked for: \") + chalk.dim(\"~/.claude/projects/\")\n );\n console.log();\n console.log(chalk.white(\" To get started:\"));\n console.log(\n chalk.dim(\" 1. Install Claude Code → \") + chalk.cyan(\"https://claude.ai/code\")\n );\n console.log(\n chalk.dim(\" 2. Have a conversation with Claude in any project\")\n );\n console.log(\n chalk.dim(\" 3. Come back and run \") + chalk.cyan(\"devlog\") + chalk.dim(\" again\")\n );\n console.log();\n return;\n }\n\n if (!isJsonMode()) {\n printSuccess(\"Found Claude Code\");\n }\n\n const config = initConfig();\n\n if (!isJsonMode()) {\n printSuccess(\"Created config at \" + chalk.dim(\"~/.devlog/\"));\n }\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Scanning your Claude Code history...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n const stats = computeStats(projects);\n spinner?.stop();\n\n if (isJsonMode()) {\n outputJson({ status: \"initialized\", configPath: getDevlogDir() + \"/config.toml\", stats: { totalProjects: stats.totalProjects, totalSessions: stats.totalSessions, totalMessages: stats.totalMessages } });\n return;\n }\n\n printSuccess(\"Scan complete\");\n console.log();\n\n renderStatsBox(stats);\n\n console.log(\n chalk.white(\" You're all set! Run \") +\n chalk.cyan.bold(\"devlog\") +\n chalk.white(\" to see your dashboard.\")\n );\n console.log();\n}\n\nfunction renderStatsBox(stats: ReturnType): void {\n const w = 42;\n const line = (label: string, value: string) => {\n const padding = w - label.length - value.length - 6;\n return (\n chalk.dim(\" │ \") +\n chalk.white(label) +\n \" \".repeat(Math.max(1, padding)) +\n chalk.cyan.bold(value) +\n chalk.dim(\" │\")\n );\n };\n\n const costStr = stats.totalCostUSD > 0\n ? stats.totalCostUSD < 1\n ? `$${stats.totalCostUSD.toFixed(3)}`\n : `$${stats.totalCostUSD.toFixed(2)}`\n : \"\";\n\n console.log(chalk.dim(\" ┌\" + \"─\".repeat(w) + \"┐\"));\n console.log(line(\"Projects\", formatNumber(stats.totalProjects)));\n console.log(line(\"Conversations\", formatNumber(stats.totalSessions)));\n console.log(line(\"Messages\", formatNumber(stats.totalMessages)));\n console.log(line(\"Commands run\", formatNumber(stats.totalToolCalls)));\n console.log(\n line(\"Files touched\", formatNumber(stats.allFilesReferenced.length))\n );\n if (costStr) {\n console.log(line(\"Total cost\", costStr));\n }\n console.log(chalk.dim(\" └\" + \"─\".repeat(w) + \"┘\"));\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects, computeStats } from \"../../core/discovery.js\";\nimport type { Session, GlobalOptions, SessionsJson } from \"../../core/types.js\";\nimport {\n formatSmartTime,\n truncate,\n formatNumber,\n costWithContext,\n messageCountContext,\n toolCountContext,\n fileCountContext,\n} from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\nimport { toSessionJson } from \"./shared\";\n\ninterface SessionsOptions {\n project?: string;\n limit?: string;\n all?: boolean;\n}\n\nexport async function sessionsCommand(options: SessionsOptions, globalOpts: GlobalOptions): Promise {\n const { config, isFirstRun } = ensureInit();\n const limit = options.all ? Infinity : parseInt(options.limit || \"30\", 10);\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Scanning sessions...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n const stats = computeStats(projects);\n spinner?.stop();\n\n if (projects.length === 0) {\n if (isJsonMode()) {\n outputJson({ projects: [] });\n return;\n }\n console.log();\n console.log(chalk.white(\" No sessions found yet.\"));\n console.log(\n chalk.dim(\" Start a Claude Code session in any project, then come back!\")\n );\n console.log();\n return;\n }\n\n // Filter by project if specified\n const filteredProjects = options.project\n ? projects.filter(\n (p) =>\n p.name.toLowerCase().includes(options.project!.toLowerCase()) ||\n p.path.toLowerCase().includes(options.project!.toLowerCase())\n )\n : projects;\n\n // ── JSON output ────────────────────────────────────\n if (isJsonMode()) {\n const data: SessionsJson = {\n projects: filteredProjects.map((p) => ({\n name: p.name,\n path: p.path,\n sessionCount: p.sessionCount,\n sessions: p.sessions.map(toSessionJson),\n })),\n };\n outputJson(data);\n return;\n }\n\n if (filteredProjects.length === 0) {\n console.log();\n console.log(\n chalk.yellow(\" No projects matching \") +\n chalk.white(`\"${options.project}\"`)\n );\n console.log();\n console.log(chalk.white(\" Your projects:\"));\n for (const p of projects) {\n console.log(\n chalk.cyan(` ${p.name}`) +\n chalk.dim(` — ${p.sessionCount} session${p.sessionCount === 1 ? \"\" : \"s\"}`)\n );\n }\n console.log();\n console.log(\n chalk.dim(\" Try: \") +\n chalk.cyan(`devlog sessions -p ${projects[0].name}`)\n );\n console.log();\n return;\n }\n\n // Header\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") +\n chalk.bold.white(\" All Sessions\") +\n (options.project ? chalk.dim(` matching \"${options.project}\"`) : \"\")\n );\n console.log(\n chalk.dim(\n ` ${formatNumber(stats.totalProjects)} projects · ${formatNumber(stats.totalSessions)} conversations · ${formatNumber(stats.totalMessages)} messages`\n )\n );\n console.log();\n\n if (isFirstRun) {\n console.log(\n chalk.dim(\" Each project shows your Claude conversations, newest first.\")\n );\n console.log(\n chalk.dim(\" Pick one with \") +\n chalk.cyan(\"devlog show \") +\n chalk.dim(\" to see the full chat.\")\n );\n console.log();\n }\n\n let displayedCount = 0;\n let sessionIndex = 0;\n\n for (const project of filteredProjects) {\n if (displayedCount >= limit) break;\n\n const sessionWord = project.sessionCount === 1 ? \"session\" : \"sessions\";\n console.log(\n chalk.bold.white(\" 📁 \" + project.name) +\n chalk.dim(` — ${project.sessionCount} ${sessionWord}`)\n );\n console.log(chalk.dim(\" \" + project.path));\n console.log();\n\n const sessionsToShow = project.sessions.slice(0, limit - displayedCount);\n\n for (const session of sessionsToShow) {\n sessionIndex++;\n renderSessionRow(session, sessionIndex);\n displayedCount++;\n }\n\n if (project.sessions.length > sessionsToShow.length) {\n const remaining = project.sessions.length - sessionsToShow.length;\n console.log(\n chalk.dim(` + ${remaining} more — use `) +\n chalk.cyan(\"--all\") +\n chalk.dim(\" to show all\")\n );\n console.log();\n }\n }\n\n // Footer\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog show 1\") +\n chalk.dim(\" view most recent · \") +\n chalk.cyan(\"devlog sessions -p \") +\n chalk.dim(\" filter\")\n );\n console.log();\n}\n\nfunction renderSessionRow(session: Session, index: number): void {\n const m = session.meta;\n const time = formatSmartTime(session.updatedAt);\n const preview = m.firstUserMessage\n ? truncate(m.firstUserMessage.replace(/\\n/g, \" \").trim(), 46)\n : chalk.dim(\"(empty)\");\n\n const indexStr = chalk.dim(`${index}.`.padEnd(4));\n console.log(\n chalk.dim(\" \") + indexStr + chalk.white(time.padEnd(16)) + chalk.white(preview)\n );\n\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls));\n if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n if (m.errorCount > 0) {\n parts.push(chalk.red(`${m.errorCount} error${m.errorCount === 1 ? \"\" : \"s\"}`));\n }\n\n console.log(\n chalk.dim(\" \") + \" \" + \" \".repeat(16) + parts.join(chalk.dim(\" · \"))\n );\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects } from \"../../core/discovery.js\";\nimport { parseSessionFile } from \"../../core/parser.js\";\nimport type { Session, DevLogEvent, GlobalOptions, ShowJson } from \"../../core/types.js\";\nimport {\n formatSmartTime,\n truncate,\n costWithContext,\n messageCountContext,\n toolCountContext,\n fileCountContext,\n humanizeToolSummary,\n} from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\n\ninterface ShowOptions {\n limit?: string;\n summary?: boolean;\n}\n\n/**\n * `devlog show ` — view a full conversation.\n * Accepts partial session IDs (first 6+ chars) for convenience.\n * Also accepts a number (1, 2, 3...) to pick from the most recent sessions.\n */\nexport async function showCommand(\n sessionRef: string,\n options: ShowOptions,\n globalOpts: GlobalOptions\n): Promise {\n const { config } = ensureInit();\n const limit = parseInt(options.limit || \"50\", 10);\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Finding session...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n spinner?.stop();\n\n // Flatten all sessions\n const allSessions: Session[] = [];\n for (const project of projects) {\n allSessions.push(...project.sessions);\n }\n allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n\n if (allSessions.length === 0) {\n if (isJsonMode()) {\n outputJson({ error: \"No sessions found\" });\n process.exit(1);\n }\n console.log();\n console.log(chalk.yellow(\" No sessions found.\"));\n console.log();\n return;\n }\n\n // Find the session — by number index or by ID prefix\n let session: Session | undefined;\n\n const asNumber = parseInt(sessionRef, 10);\n if (!isNaN(asNumber) && asNumber >= 1 && asNumber <= allSessions.length) {\n session = allSessions[asNumber - 1];\n } else {\n const ref = sessionRef.toLowerCase();\n // Try prefix match first, then substring match\n session = allSessions.find((s) =>\n s.id.toLowerCase().startsWith(ref)\n );\n if (!session) {\n session = allSessions.find((s) =>\n s.id.toLowerCase().includes(ref)\n );\n }\n }\n\n if (!session) {\n if (isJsonMode()) {\n outputJson({ error: `No session matching: ${sessionRef}` });\n process.exit(1);\n }\n console.log();\n console.log(\n chalk.yellow(\" Couldn't find a session matching: \") +\n chalk.white(sessionRef)\n );\n console.log();\n console.log(chalk.dim(\" Recent sessions:\"));\n const recent = allSessions.slice(0, 5);\n recent.forEach((s, i) => {\n const preview = s.meta.firstUserMessage\n ? truncate(s.meta.firstUserMessage.replace(/\\n/g, \" \").trim(), 40)\n : \"(empty)\";\n console.log(\n chalk.cyan(` ${i + 1}. `) +\n chalk.white(s.projectName.padEnd(14)) +\n chalk.dim(preview) +\n chalk.dim(` [${s.id.slice(0, 8)}]`)\n );\n });\n console.log();\n console.log(\n chalk.dim(\" Use \") +\n chalk.cyan(\"devlog show 1\") +\n chalk.dim(\" to view the most recent session.\")\n );\n console.log();\n process.exit(1);\n }\n\n // Parse the full session\n let parseSpinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n parseSpinner = ora({\n text: chalk.dim(\" Reading conversation...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const events = await parseSessionFile(session.filePath, session.id);\n parseSpinner?.stop();\n\n // ── JSON output ────────────────────────────────────\n if (isJsonMode()) {\n const data: ShowJson = {\n session: {\n id: session.id,\n projectName: session.projectName,\n meta: session.meta,\n },\n events: events.map((e) => ({\n timestamp: e.timestamp.toISOString(),\n role: e.role,\n type: e.type,\n content: e.content,\n ...(e.toolName ? { toolName: e.toolName } : {}),\n ...(e.isError ? { isError: e.isError } : {}),\n })),\n };\n outputJson(data);\n return;\n }\n\n // Render\n if (options.summary) {\n renderSummary(session, events);\n } else {\n renderSessionHeader(session);\n renderConversation(events, limit);\n renderSessionFooter(session, events, limit);\n }\n}\n\nfunction renderSessionHeader(session: Session): void {\n const m = session.meta;\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") +\n chalk.bold.white(` ${session.projectName}`) +\n chalk.dim(\" · \") +\n chalk.dim(formatSmartTime(session.updatedAt))\n );\n console.log();\n\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls));\n if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n\n console.log(chalk.dim(\" \") + parts.join(chalk.dim(\" · \")));\n\n if (m.uniqueTools.length > 0) {\n console.log(\n chalk.dim(\" \") + humanizeToolSummary(m.uniqueTools)\n );\n }\n\n console.log();\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n}\n\nfunction formatToolLine(event: DevLogEvent): string {\n const name = event.toolName || \"tool\";\n const input = event.toolInput || {};\n\n if (name === \"Read\" && input.file_path) return `read ${input.file_path}`;\n if (name === \"Write\" && input.file_path) return `wrote ${input.file_path}`;\n if (name === \"Edit\" && input.file_path) return `edited ${input.file_path}`;\n if (name === \"Bash\" && input.command) return `ran: ${truncate(String(input.command), 60)}`;\n if (name === \"Grep\" && input.pattern) return `searched for \"${truncate(String(input.pattern), 40)}\"`;\n if (name === \"Glob\" && input.pattern) return `found files matching ${truncate(String(input.pattern), 40)}`;\n\n // Fallback: humanize\n return name.replace(/([a-z])([A-Z])/g, \"$1 $2\").toLowerCase();\n}\n\nfunction flushToolGroup(group: DevLogEvent[]): void {\n if (group.length === 0) return;\n\n const firstName = group[0].toolName || \"tool\";\n const allSame = group.every((e) => e.toolName === firstName);\n\n if (allSame && group.length > 2 && (firstName === \"Read\" || firstName === \"Write\" || firstName === \"Edit\")) {\n // Group consecutive same-type file operations\n const verb = firstName === \"Read\" ? \"read\" : firstName === \"Write\" ? \"wrote\" : \"edited\";\n const files = group\n .map((e) => {\n const p = String(e.toolInput?.file_path || \"\");\n return p.split(\"/\").pop() || p;\n })\n .filter(Boolean);\n const fileWord = group.length === 1 ? \"file\" : \"files\";\n console.log(\n chalk.green(\" ▸ \") +\n chalk.dim(`${verb} ${group.length} ${fileWord}: ${truncate(files.join(\", \"), 60)}`)\n );\n } else {\n for (const event of group) {\n console.log(\n chalk.green(\" ▸ \") + chalk.dim(formatToolLine(event))\n );\n }\n }\n}\n\nfunction renderConversation(events: DevLogEvent[], limit: number): void {\n let shown = 0;\n let toolGroup: DevLogEvent[] = [];\n\n for (const event of events) {\n if (shown >= limit) break;\n\n // Flush tool group on non-tool event\n if (event.role !== \"tool_use\" && event.role !== \"tool_result\" && toolGroup.length > 0) {\n flushToolGroup(toolGroup);\n toolGroup = [];\n }\n\n if (event.role === \"human\" && (event.type === \"text\" || event.type === \"message\")) {\n console.log(\n chalk.blue.bold(\" You: \") +\n chalk.white(truncate(event.content.trim(), 76))\n );\n console.log();\n shown++;\n } else if (event.role === \"assistant\" && event.type === \"text\") {\n const lines = event.content.trim().split(\"\\n\");\n const preview = lines.slice(0, 3);\n console.log(chalk.dim.bold(\" Claude: \"));\n for (const line of preview) {\n console.log(chalk.dim(\" \") + chalk.white(truncate(line, 74)));\n }\n if (lines.length > 3) {\n console.log(chalk.dim(` ... (${lines.length - 3} more lines)`));\n }\n console.log();\n shown++;\n } else if (event.role === \"tool_use\") {\n toolGroup.push(event);\n shown++;\n } else if (event.role === \"tool_result\") {\n if (event.isError) {\n console.log(\n chalk.red(\" ✗ Error: \") +\n chalk.dim(truncate(event.content, 60))\n );\n }\n }\n }\n\n // Flush remaining tool group\n if (toolGroup.length > 0) {\n flushToolGroup(toolGroup);\n }\n}\n\nfunction renderSessionFooter(\n session: Session,\n events: DevLogEvent[],\n limit: number\n): void {\n const totalEvents = events.filter(\n (e) =>\n (e.role === \"human\" && (e.type === \"text\" || e.type === \"message\")) ||\n (e.role === \"assistant\" && e.type === \"text\") ||\n e.role === \"tool_use\"\n ).length;\n\n console.log();\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n\n if (totalEvents > limit) {\n console.log(\n chalk.dim(` Showing ${limit} of ${totalEvents} events. Use `) +\n chalk.cyan(`devlog show ${session.id.slice(0, 8)} -n ${totalEvents}`) +\n chalk.dim(\" to see all.\")\n );\n }\n\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(`devlog sessions -p ${session.projectName}`) +\n chalk.dim(\" other sessions in this project\")\n );\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog\") +\n chalk.dim(\" back to dashboard\")\n );\n console.log();\n}\n\nfunction renderSummary(session: Session, events: DevLogEvent[]): void {\n const m = session.meta;\n\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") +\n chalk.bold.white(` ${session.projectName}`) +\n chalk.dim(\" · \") +\n chalk.dim(formatSmartTime(session.updatedAt))\n );\n console.log();\n\n // Extract what was asked\n const firstMsg = m.firstUserMessage\n ? truncate(m.firstUserMessage.replace(/\\n/g, \" \").trim(), 70)\n : \"(empty)\";\n console.log(chalk.white(\" Summary:\"));\n console.log(\n chalk.dim(\" You asked Claude: \") + chalk.white(`\"${firstMsg}\"`)\n );\n console.log();\n\n // What happened — group tool usage\n const toolGroups = new Map();\n const filesChanged = new Set();\n const commandsRun: string[] = [];\n let errorCount = 0;\n\n for (const event of events) {\n if (event.role === \"tool_use\") {\n const name = event.toolName || \"tool\";\n toolGroups.set(name, (toolGroups.get(name) || 0) + 1);\n\n const input = event.toolInput || {};\n if (input.file_path && (name === \"Write\" || name === \"Edit\")) {\n filesChanged.add(String(input.file_path));\n }\n if (name === \"Bash\" && input.command) {\n commandsRun.push(truncate(String(input.command), 50));\n }\n }\n if (event.role === \"tool_result\" && event.isError) {\n errorCount++;\n }\n }\n\n console.log(chalk.white(\" What happened:\"));\n\n for (const [name, count] of toolGroups) {\n let desc: string;\n if (name === \"Read\") desc = `Read ${count} file${count === 1 ? \"\" : \"s\"} to understand the codebase`;\n else if (name === \"Write\") desc = `Created ${count} file${count === 1 ? \"\" : \"s\"}`;\n else if (name === \"Edit\") desc = `Edited ${count} file${count === 1 ? \"\" : \"s\"}`;\n else if (name === \"Bash\") desc = `Ran ${count} command${count === 1 ? \"\" : \"s\"}` + (commandsRun.length > 0 ? ` (${truncate(commandsRun.slice(0, 3).join(\", \"), 40)})` : \"\");\n else if (name === \"Grep\") desc = `Searched code ${count} time${count === 1 ? \"\" : \"s\"}`;\n else if (name === \"Glob\") desc = `Searched for files ${count} time${count === 1 ? \"\" : \"s\"}`;\n else desc = `${name} ×${count}`;\n\n console.log(chalk.dim(\" - \") + chalk.dim(desc));\n }\n\n if (filesChanged.size > 0) {\n const fileNames = [...filesChanged].map((f) => f.split(\"/\").pop() || f);\n console.log(\n chalk.dim(\" - \") +\n chalk.dim(`Files changed: ${truncate(fileNames.join(\", \"), 50)}`)\n );\n }\n\n if (errorCount > 0) {\n console.log(\n chalk.dim(\" - \") +\n chalk.red(`Fixed ${errorCount} error${errorCount === 1 ? \"\" : \"s\"}`)\n );\n }\n\n console.log();\n\n // Stats line\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls));\n if (m.filesReferenced.length > 0) parts.push(fileCountContext(m.filesReferenced.length));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n\n console.log(chalk.dim(\" \") + parts.join(chalk.dim(\" · \")));\n\n // Footer\n console.log();\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(`devlog show ${session.id.slice(0, 8)}`) +\n chalk.dim(\" see full conversation · \") +\n chalk.cyan(`devlog sessions -p ${session.projectName}`) +\n chalk.dim(\" other sessions\")\n );\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport dayjs from \"dayjs\";\nimport isToday from \"dayjs/plugin/isToday.js\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects } from \"../../core/discovery.js\";\nimport type { Session, GlobalOptions } from \"../../core/types.js\";\nimport {\n formatSmartTime,\n truncate,\n costWithContext,\n messageCountContext,\n toolCountContext,\n fileCountContext,\n} from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\nimport { toSessionJson } from \"./shared\";\n\ndayjs.extend(isToday);\n\nexport async function todayCommand(globalOpts: GlobalOptions): Promise {\n const { config } = ensureInit();\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Checking today's sessions...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n spinner?.stop();\n\n // Filter to today's sessions\n const todaySessions: Session[] = [];\n const projectNames = new Set();\n\n for (const project of projects) {\n for (const session of project.sessions) {\n if (dayjs(session.updatedAt).isToday()) {\n todaySessions.push(session);\n projectNames.add(session.projectName);\n }\n }\n }\n\n todaySessions.sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime());\n\n // JSON output\n if (isJsonMode()) {\n const totalCost = todaySessions.reduce((s, sess) => s + sess.meta.totalCostUSD, 0);\n const totalTools = todaySessions.reduce((s, sess) => s + sess.meta.toolCalls, 0);\n const allFiles = new Set();\n for (const s of todaySessions) {\n for (const f of s.meta.filesReferenced) allFiles.add(f);\n }\n\n outputJson({\n date: dayjs().format(\"YYYY-MM-DD\"),\n sessionCount: todaySessions.length,\n projectCount: projectNames.size,\n totalCostUSD: Math.round(totalCost * 1000000) / 1000000,\n totalToolCalls: totalTools,\n totalFilesTouched: allFiles.size,\n sessions: todaySessions.map(toSessionJson),\n });\n return;\n }\n\n // No sessions today\n if (todaySessions.length === 0) {\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" Your day so far\")\n );\n console.log();\n console.log(chalk.dim(\" No sessions yet today.\"));\n\n // Find most recent session\n const allSessions: Session[] = [];\n for (const p of projects) allSessions.push(...p.sessions);\n allSessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n\n if (allSessions.length > 0) {\n const last = allSessions[0];\n console.log(\n chalk.dim(\" Your last session was \") +\n chalk.white(formatSmartTime(last.updatedAt)) +\n chalk.dim(\" in \") +\n chalk.cyan(last.projectName)\n );\n }\n\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog sessions\") +\n chalk.dim(\" browse all · \") +\n chalk.cyan(\"devlog\") +\n chalk.dim(\" dashboard\")\n );\n console.log();\n return;\n }\n\n // Narrative summary\n const totalCost = todaySessions.reduce((s, sess) => s + sess.meta.totalCostUSD, 0);\n const totalTools = todaySessions.reduce((s, sess) => s + sess.meta.toolCalls, 0);\n const allFiles = new Set();\n for (const s of todaySessions) {\n for (const f of s.meta.filesReferenced) allFiles.add(f);\n }\n\n const sessionWord = todaySessions.length === 1 ? \"conversation\" : \"conversations\";\n const projectWord = projectNames.size === 1 ? \"project\" : \"projects\";\n\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" Your day so far\")\n );\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.white(`${todaySessions.length} ${sessionWord} across ${projectNames.size} ${projectWord}.`)\n );\n\n const summaryParts: string[] = [];\n if (totalTools > 0) summaryParts.push(toolCountContext(totalTools));\n if (allFiles.size > 0) summaryParts.push(fileCountContext(allFiles.size));\n if (summaryParts.length > 0) {\n console.log(chalk.dim(\" \") + chalk.white(\"Claude \") + summaryParts.join(chalk.dim(\" and \")));\n }\n if (totalCost > 0) {\n console.log(chalk.dim(\" Cost: \") + costWithContext(totalCost));\n }\n\n console.log();\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n\n // Timeline\n for (const session of todaySessions) {\n const m = session.meta;\n const time = formatSmartTime(session.updatedAt);\n const preview = m.firstUserMessage\n ? truncate(m.firstUserMessage.replace(/\\n/g, \" \").trim(), 42)\n : chalk.dim(\"(empty)\");\n\n console.log(\n chalk.dim(\" \") +\n chalk.white(time.padEnd(12)) +\n chalk.cyan(session.projectName.padEnd(14)) +\n chalk.white(`\"${preview}\"`)\n );\n\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.toolCalls > 0) parts.push(toolCountContext(m.toolCalls));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n\n console.log(\n chalk.dim(\" \") +\n \" \".repeat(26) +\n parts.join(chalk.dim(\" · \"))\n );\n console.log();\n }\n\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog show 1\") +\n chalk.dim(\" view most recent · \") +\n chalk.cyan(\"devlog sessions\") +\n chalk.dim(\" browse all\")\n );\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects } from \"../../core/discovery.js\";\nimport type { Session, GlobalOptions } from \"../../core/types.js\";\nimport {\n formatSmartTime,\n truncate,\n costWithContext,\n messageCountContext,\n} from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\nimport { toSessionJson } from \"./shared\";\n\nexport async function searchCommand(\n query: string,\n globalOpts: GlobalOptions\n): Promise {\n const { config } = ensureInit();\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Searching sessions...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n spinner?.stop();\n\n const q = query.toLowerCase();\n\n // Search by first message, project name, or tool names\n const matches: Session[] = [];\n for (const project of projects) {\n for (const session of project.sessions) {\n const m = session.meta;\n if (\n session.projectName.toLowerCase().includes(q) ||\n m.firstUserMessage.toLowerCase().includes(q) ||\n m.uniqueTools.some((t) => t.toLowerCase().includes(q))\n ) {\n matches.push(session);\n }\n }\n }\n\n matches.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n\n // JSON output\n if (isJsonMode()) {\n outputJson({\n query,\n matchCount: matches.length,\n sessions: matches.map(toSessionJson),\n });\n return;\n }\n\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") +\n chalk.bold.white(` Search: `) +\n chalk.white(`\"${query}\"`)\n );\n console.log();\n\n if (matches.length === 0) {\n console.log(chalk.dim(\" No conversations found matching that query.\"));\n console.log();\n console.log(\n chalk.dim(\" Try a shorter term, or use \") +\n chalk.cyan(\"devlog sessions\") +\n chalk.dim(\" to browse all.\")\n );\n console.log();\n return;\n }\n\n const matchWord = matches.length === 1 ? \"conversation\" : \"conversations\";\n console.log(\n chalk.dim(` Found ${matches.length} ${matchWord} matching \"${query}\"`)\n );\n console.log();\n\n const shown = matches.slice(0, 20);\n\n for (let i = 0; i < shown.length; i++) {\n const session = shown[i];\n const m = session.meta;\n const time = formatSmartTime(session.updatedAt);\n const preview = m.firstUserMessage\n ? truncate(m.firstUserMessage.replace(/\\n/g, \" \").trim(), 42)\n : chalk.dim(\"(empty)\");\n\n console.log(\n chalk.dim(` ${(i + 1).toString().padEnd(3)} `) +\n chalk.white(time.padEnd(16)) +\n chalk.cyan(session.projectName.padEnd(14)) +\n chalk.white(`\"${preview}\"`)\n );\n\n const turns = m.humanTurns + m.assistantTurns;\n const parts: string[] = [];\n parts.push(messageCountContext(turns));\n if (m.totalCostUSD > 0) parts.push(costWithContext(m.totalCostUSD));\n\n console.log(\n chalk.dim(\" \") +\n \" \" +\n \" \".repeat(16) +\n parts.join(chalk.dim(\" · \"))\n );\n console.log();\n }\n\n if (matches.length > 20) {\n console.log(chalk.dim(` + ${matches.length - 20} more matches`));\n console.log();\n }\n\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog show 1\") +\n chalk.dim(\" view match · \") +\n chalk.cyan(`devlog search \"${query} ...\"`) +\n chalk.dim(\" refine\")\n );\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport dayjs from \"dayjs\";\nimport isToday from \"dayjs/plugin/isToday.js\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects, computeStats } from \"../../core/discovery.js\";\nimport type { Session, GlobalOptions, AggregateStats } from \"../../core/types.js\";\nimport {\n formatNumber,\n costWithContext,\n} from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\nimport { updateCacheFromStats } from \"../../core/cache.js\";\n\ndayjs.extend(isToday);\n\ninterface StatsOptions {\n period?: string;\n}\n\nfunction filterByPeriod(sessions: Session[], period: string): Session[] {\n const now = dayjs();\n return sessions.filter((s) => {\n const d = dayjs(s.updatedAt);\n switch (period) {\n case \"today\":\n return d.isToday();\n case \"week\":\n return now.diff(d, \"day\") < 7;\n case \"month\":\n return now.diff(d, \"day\") < 30;\n default:\n return true;\n }\n });\n}\n\nexport async function statsCommand(\n options: StatsOptions,\n globalOpts: GlobalOptions\n): Promise {\n const { config } = ensureInit();\n const period = options.period || \"all\";\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Crunching numbers...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const projects = await discoverProjects(config.claudeDir);\n spinner?.stop();\n\n // Update cache as side effect of full scan\n if (projects.length > 0) {\n updateCacheFromStats(computeStats(projects));\n }\n\n const allSessions: Session[] = [];\n for (const p of projects) allSessions.push(...p.sessions);\n const filtered = filterByPeriod(allSessions, period);\n\n // Aggregate\n let totalCost = 0;\n let totalTools = 0;\n let totalMessages = 0;\n const fileSet = new Set();\n const toolCounts = new Map();\n const projectCounts = new Map();\n const costByModel: Record = {};\n\n for (const s of filtered) {\n totalCost += s.meta.totalCostUSD;\n totalTools += s.meta.toolCalls;\n totalMessages += s.meta.humanTurns + s.meta.assistantTurns;\n for (const f of s.meta.filesReferenced) fileSet.add(f);\n for (const t of s.meta.uniqueTools) {\n toolCounts.set(t, (toolCounts.get(t) || 0) + 1);\n }\n projectCounts.set(\n s.projectName,\n (projectCounts.get(s.projectName) || 0) + 1\n );\n for (const [model, cost] of Object.entries(s.meta.costByModel)) {\n costByModel[model] = (costByModel[model] || 0) + cost;\n }\n }\n\n const periodLabel =\n period === \"today\"\n ? \"Today\"\n : period === \"week\"\n ? \"This Week\"\n : period === \"month\"\n ? \"This Month\"\n : \"All Time\";\n\n // JSON\n if (isJsonMode()) {\n outputJson({\n period: periodLabel,\n sessionCount: filtered.length,\n totalMessages,\n totalToolCalls: totalTools,\n totalFilesTouched: fileSet.size,\n totalCostUSD: Math.round(totalCost * 1000000) / 1000000,\n topTools: [...toolCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([name, count]) => ({ name, count })),\n projectBreakdown: [...projectCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([name, count]) => ({ name, sessions: count })),\n costByModel,\n });\n return;\n }\n\n if (filtered.length === 0) {\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(` Stats — ${periodLabel}`)\n );\n console.log();\n console.log(chalk.dim(\" No sessions in this period.\"));\n console.log();\n return;\n }\n\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(` Stats — ${periodLabel}`)\n );\n console.log();\n\n // Stats box\n const w = 42;\n const line = (label: string, value: string) => {\n const padding = w - label.length - value.length - 6;\n return (\n chalk.dim(\" │ \") +\n chalk.white(label) +\n \" \".repeat(Math.max(1, padding)) +\n chalk.cyan.bold(value) +\n chalk.dim(\" │\")\n );\n };\n\n console.log(chalk.dim(\" ┌\" + \"─\".repeat(w) + \"┐\"));\n console.log(line(\"Sessions\", formatNumber(filtered.length)));\n console.log(line(\"Messages\", formatNumber(totalMessages)));\n console.log(line(\"Commands run\", formatNumber(totalTools)));\n console.log(line(\"Files touched\", formatNumber(fileSet.size)));\n if (totalCost > 0) {\n const costStr = totalCost < 1 ? `$${totalCost.toFixed(3)}` : `$${totalCost.toFixed(2)}`;\n console.log(line(\"Total cost\", costStr));\n }\n console.log(chalk.dim(\" └\" + \"─\".repeat(w) + \"┘\"));\n console.log();\n\n // Top tools\n const topTools = [...toolCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5);\n if (topTools.length > 0) {\n console.log(chalk.white(\" Most used tools:\"));\n for (const [name, count] of topTools) {\n console.log(\n chalk.dim(\" \") +\n chalk.green(name.padEnd(16)) +\n chalk.dim(`used in ${count} session${count === 1 ? \"\" : \"s\"}`)\n );\n }\n console.log();\n }\n\n // Most active project\n const topProjects = [...projectCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3);\n if (topProjects.length > 0) {\n console.log(chalk.white(\" Most active projects:\"));\n for (const [name, count] of topProjects) {\n const sessionWord = count === 1 ? \"session\" : \"sessions\";\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(name.padEnd(16)) +\n chalk.dim(`${count} ${sessionWord}`)\n );\n }\n console.log();\n }\n\n // Cost context\n if (totalCost > 0) {\n console.log(\n chalk.dim(\" Total cost: \") + costWithContext(totalCost)\n );\n console.log();\n }\n\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog cost\") +\n chalk.dim(\" cost breakdown · \") +\n chalk.cyan(\"devlog stats --period week\") +\n chalk.dim(\" filter\")\n );\n console.log();\n}\n","import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { buildCostReport, type CostPeriodTotals, type CostReport } from \"../../core/cost-tracker.js\";\nimport type { GlobalOptions } from \"../../core/types.js\";\nimport { costWithContext } from \"../utils/format.js\";\nimport { outputJson, isJsonMode, isQuietMode } from \"../utils/output.js\";\n\ninterface CostOptions {\n period?: string;\n}\n\ntype PeriodKey = \"today\" | \"week\" | \"allTime\";\n\nfunction normalizePeriod(period: string | undefined): PeriodKey {\n switch (period) {\n case \"today\":\n return \"today\";\n case \"week\":\n return \"week\";\n default:\n return \"allTime\";\n }\n}\n\nfunction periodLabel(period: PeriodKey): string {\n if (period === \"today\") return \"Today\";\n if (period === \"week\") return \"This Week\";\n return \"All Time\";\n}\n\nfunction renderBar(fraction: number, width: number = 16): string {\n const filled = Math.round(Math.max(0, Math.min(1, fraction)) * width);\n return chalk.green(\"█\".repeat(filled)) + chalk.dim(\"░\".repeat(width - filled));\n}\n\nfunction formatUsd(value: number): string {\n if (value <= 0) return \"$0.000\";\n return value < 1 ? `$${value.toFixed(3)}` : `$${value.toFixed(2)}`;\n}\n\nfunction formatCredits(value: number): string {\n if (value <= 0) return \"0 credits\";\n return `${value < 10 ? value.toFixed(2) : value.toFixed(1)} credits`;\n}\n\nexport async function costCommand(\n options: CostOptions,\n _globalOpts: GlobalOptions\n): Promise {\n const period = normalizePeriod(options.period);\n\n let spinner: ReturnType | null = null;\n if (!isJsonMode() && !isQuietMode()) {\n spinner = ora({\n text: chalk.dim(\" Calculating costs...\"),\n spinner: \"dots\",\n color: \"cyan\",\n stream: process.stderr,\n }).start();\n }\n\n const report = await buildCostReport();\n spinner?.stop();\n\n if (isJsonMode()) {\n outputJson(report);\n return;\n }\n\n renderReport(report, period);\n}\n\nfunction renderReport(report: CostReport, period: PeriodKey): void {\n const total = report.totals[period];\n\n console.log();\n console.log(\n chalk.bold.cyan(\" ▌\") + chalk.bold.white(` Cost Breakdown — ${periodLabel(period)}`)\n );\n console.log();\n\n if (total.apiCostUSD === 0 && total.subscriptionCredits === 0) {\n console.log(chalk.dim(\" No costs recorded in this period.\"));\n console.log();\n return;\n }\n\n console.log(chalk.dim(\" API estimate: \") + costWithContext(total.apiCostUSD));\n if (total.subscriptionCredits > 0) {\n console.log(chalk.dim(\" Subscription usage: \") + chalk.yellow(formatCredits(total.subscriptionCredits)));\n }\n console.log(chalk.dim(\" Tokens: \") + chalk.white(total.totalTokens.toLocaleString()));\n console.log();\n\n renderQuota(report);\n renderProviders(report, period, total);\n renderProjects(report, period, total);\n\n console.log(chalk.dim(\" \" + \"─\".repeat(60)));\n console.log();\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"devlog cost --json\") +\n chalk.dim(\" full report · \") +\n chalk.cyan(\"devlog cost --period week\") +\n chalk.dim(\" weekly view\")\n );\n console.log();\n}\n\nfunction renderQuota(report: CostReport): void {\n if (report.quota.length === 0) return;\n\n console.log(chalk.white(\" Quota:\"));\n for (const q of report.quota) {\n const label = q.name === \"primary\" ? \"daily/window\" : \"weekly\";\n const reset = q.resetsAt ? ` resets ${new Date(q.resetsAt).toLocaleString()}` : \"\";\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(label.padEnd(14)) +\n chalk.yellow(`${q.usedPercent.toFixed(1)}% used`.padEnd(14)) +\n chalk.dim(`${q.remainingPercent.toFixed(1)}% left`) +\n chalk.dim(reset)\n );\n }\n console.log();\n}\n\nfunction renderProviders(report: CostReport, period: PeriodKey, total: CostPeriodTotals): void {\n console.log(chalk.white(\" By provider:\"));\n for (const provider of report.providers) {\n const p = provider[period];\n if (p.apiCostUSD === 0 && p.subscriptionCredits === 0) continue;\n const pct = total.apiCostUSD > 0 ? p.apiCostUSD / total.apiCostUSD : 0;\n const label = provider.provider === \"claude_code\" ? \"Claude Code\" : \"Codex\";\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(label.padEnd(18)) +\n chalk.yellow(formatUsd(p.apiCostUSD).padEnd(10)) +\n chalk.dim(formatCredits(p.subscriptionCredits).padEnd(15)) +\n renderBar(pct)\n );\n }\n console.log();\n}\n\nfunction renderProjects(report: CostReport, period: PeriodKey, total: CostPeriodTotals): void {\n console.log(chalk.white(\" By project:\"));\n for (const project of report.projects.slice(0, 12)) {\n const p = project[period];\n if (p.apiCostUSD === 0 && p.subscriptionCredits === 0) continue;\n const pct = total.apiCostUSD > 0 ? p.apiCostUSD / total.apiCostUSD : 0;\n const name = project.projectName.length > 24 ? `${project.projectName.slice(0, 23)}…` : project.projectName;\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(name.padEnd(25)) +\n chalk.yellow(formatUsd(p.apiCostUSD).padEnd(10)) +\n chalk.dim(formatCredits(p.subscriptionCredits).padEnd(15)) +\n renderBar(pct)\n );\n }\n console.log();\n}\n","import { readdir, stat } from \"fs/promises\";\nimport { createReadStream } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { basename, join } from \"path\";\nimport { homedir } from \"os\";\nimport dayjs from \"dayjs\";\nimport { discoverProjects } from \"./discovery\";\nimport type { Session } from \"./types\";\n\nexport type CostProvider = \"claude_code\" | \"codex\";\nexport type BillingMode = \"api\" | \"oauth_subscription\";\n\nexport interface CostTokenTotals {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\nexport interface CostMoneyTotals {\n apiCostUSD: number;\n subscriptionCredits: number;\n}\n\nexport interface CostPeriodTotals extends CostTokenTotals, CostMoneyTotals {\n usageEvents: number;\n}\n\nexport interface CostQuotaWindow {\n provider: CostProvider;\n name: \"primary\" | \"secondary\";\n observedAt: string;\n usedPercent: number;\n remainingPercent: number;\n windowMinutes: number;\n resetsAt: string | null;\n source: \"local_log\";\n}\n\nexport interface CostProjectSummary {\n projectName: string;\n projectPath: string;\n providers: CostProvider[];\n today: CostPeriodTotals;\n week: CostPeriodTotals;\n allTime: CostPeriodTotals;\n}\n\nexport interface CostProviderSummary {\n provider: CostProvider;\n billingModes: BillingMode[];\n today: CostPeriodTotals;\n week: CostPeriodTotals;\n allTime: CostPeriodTotals;\n quota: CostQuotaWindow[];\n}\n\nexport interface CostReport {\n generatedAt: string;\n totals: {\n today: CostPeriodTotals;\n week: CostPeriodTotals;\n allTime: CostPeriodTotals;\n };\n providers: CostProviderSummary[];\n projects: CostProjectSummary[];\n quota: CostQuotaWindow[];\n sources: {\n claudeProjectsDir: string;\n codexSessionsDir: string;\n };\n}\n\ninterface UsageRecord {\n provider: CostProvider;\n billingMode: BillingMode;\n timestamp: Date;\n sessionId: string;\n projectName: string;\n projectPath: string;\n model: string;\n tokens: CostTokenTotals;\n apiCostUSD: number;\n subscriptionCredits: number;\n}\n\ninterface CodexRateLimitWindow {\n used_percent?: number;\n window_minutes?: number;\n resets_at?: number;\n}\n\ninterface CodexTokenUsage {\n input_tokens?: number;\n cached_input_tokens?: number;\n output_tokens?: number;\n reasoning_output_tokens?: number;\n total_tokens?: number;\n}\n\nconst EMPTY_TOTALS: CostPeriodTotals = {\n usageEvents: 0,\n inputTokens: 0,\n cachedInputTokens: 0,\n outputTokens: 0,\n reasoningOutputTokens: 0,\n totalTokens: 0,\n apiCostUSD: 0,\n subscriptionCredits: 0,\n};\n\nconst CODEX_API_PRICING_USD: Record = {\n \"gpt-5.1-codex\": { input: 1.25, cachedInput: 0.125, output: 10 },\n \"gpt-5.1-codex-max\": { input: 1.25, cachedInput: 0.125, output: 10 },\n \"gpt-5-codex\": { input: 1.25, cachedInput: 0.125, output: 10 },\n};\n\nconst CODEX_CREDIT_RATES: Record = {\n \"gpt-5.5\": { input: 125, cachedInput: 12.5, output: 750 },\n \"gpt-5.4-mini\": { input: 18.75, cachedInput: 1.875, output: 113 },\n \"gpt-5.4\": { input: 62.5, cachedInput: 6.25, output: 375 },\n \"gpt-5.3-codex\": { input: 43.75, cachedInput: 4.375, output: 350 },\n \"gpt-5.2\": { input: 43.75, cachedInput: 4.375, output: 350 },\n \"gpt-5.1-codex\": { input: 43.75, cachedInput: 4.375, output: 350 },\n \"gpt-5-codex\": { input: 43.75, cachedInput: 4.375, output: 350 },\n};\n\nexport function getCodexSessionsDir(): string {\n return join(homedir(), \".codex\", \"sessions\");\n}\n\nexport function getCodexArchivedSessionsDir(): string {\n return join(homedir(), \".codex\", \"archived_sessions\");\n}\n\nexport function emptyCostTotals(): CostPeriodTotals {\n return { ...EMPTY_TOTALS };\n}\n\nexport function addCostTotals(target: CostPeriodTotals, source: CostPeriodTotals | UsageRecord): void {\n const tokens = \"tokens\" in source ? source.tokens : source;\n target.usageEvents += \"usageEvents\" in source ? source.usageEvents : 1;\n target.inputTokens += tokens.inputTokens;\n target.cachedInputTokens += tokens.cachedInputTokens;\n target.outputTokens += tokens.outputTokens;\n target.reasoningOutputTokens += tokens.reasoningOutputTokens;\n target.totalTokens += tokens.totalTokens;\n target.apiCostUSD += source.apiCostUSD;\n target.subscriptionCredits += source.subscriptionCredits;\n}\n\nexport function computeCodexApiCostUSD(model: string, tokens: CostTokenTotals): number {\n const rate = findRate(model, CODEX_API_PRICING_USD);\n return pricedTotal(tokens, rate);\n}\n\nexport function computeCodexSubscriptionCredits(model: string, tokens: CostTokenTotals): number {\n const rate = findRate(model, CODEX_CREDIT_RATES);\n return pricedTotal(tokens, rate);\n}\n\nexport async function buildCostReport(options: {\n claudeProjectsDir?: string;\n codexSessionsDir?: string;\n now?: Date;\n} = {}): Promise {\n const now = options.now ?? new Date();\n const claudeProjectsDir = options.claudeProjectsDir;\n const codexSessionsDir = options.codexSessionsDir ?? getCodexSessionsDir();\n const records: UsageRecord[] = [];\n\n const claudeProjects = await discoverProjects(claudeProjectsDir);\n for (const project of claudeProjects) {\n for (const session of project.sessions) {\n records.push(claudeSessionToRecord(session));\n }\n }\n\n const codexFiles = await listCodexSessionFiles(codexSessionsDir, codexSessionsDir === getCodexSessionsDir());\n const quota: CostQuotaWindow[] = [];\n for (const filePath of codexFiles) {\n const parsed = await scanCodexSession(filePath);\n records.push(...parsed.records);\n quota.push(...parsed.quota);\n }\n\n return aggregateCostReport(records, quota, {\n now,\n claudeProjectsDir: claudeProjectsDir ?? join(homedir(), \".claude\", \"projects\"),\n codexSessionsDir,\n });\n}\n\nexport function aggregateCostReport(\n records: UsageRecord[],\n quota: CostQuotaWindow[],\n options: { now: Date; claudeProjectsDir: string; codexSessionsDir: string }\n): CostReport {\n const todayStart = dayjs(options.now).startOf(\"day\");\n const weekStart = dayjs(options.now).subtract(7, \"day\").startOf(\"day\");\n\n const totals = {\n today: emptyCostTotals(),\n week: emptyCostTotals(),\n allTime: emptyCostTotals(),\n };\n const providers = new Map();\n const projects = new Map();\n\n for (const record of records) {\n const isToday = dayjs(record.timestamp).isAfter(todayStart) || dayjs(record.timestamp).isSame(todayStart);\n const isWeek = dayjs(record.timestamp).isAfter(weekStart) || dayjs(record.timestamp).isSame(weekStart);\n\n addCostTotals(totals.allTime, record);\n if (isToday) addCostTotals(totals.today, record);\n if (isWeek) addCostTotals(totals.week, record);\n\n const provider = getProviderSummary(providers, record.provider);\n if (!provider.billingModes.includes(record.billingMode)) provider.billingModes.push(record.billingMode);\n addCostTotals(provider.allTime, record);\n if (isToday) addCostTotals(provider.today, record);\n if (isWeek) addCostTotals(provider.week, record);\n\n const project = getProjectSummary(projects, record.projectName, record.projectPath);\n if (!project.providers.includes(record.provider)) project.providers.push(record.provider);\n addCostTotals(project.allTime, record);\n if (isToday) addCostTotals(project.today, record);\n if (isWeek) addCostTotals(project.week, record);\n }\n\n for (const provider of providers.values()) {\n provider.quota = latestQuotaForProvider(quota, provider.provider);\n }\n\n return {\n generatedAt: options.now.toISOString(),\n totals: roundReportTotals(totals),\n providers: [...providers.values()].sort((a, b) => b.allTime.apiCostUSD - a.allTime.apiCostUSD),\n projects: [...projects.values()].sort((a, b) => b.allTime.apiCostUSD - a.allTime.apiCostUSD),\n quota: latestQuotaForProvider(quota, \"codex\"),\n sources: {\n claudeProjectsDir: options.claudeProjectsDir,\n codexSessionsDir: options.codexSessionsDir,\n },\n };\n}\n\nexport async function scanCodexSession(filePath: string): Promise<{ records: UsageRecord[]; quota: CostQuotaWindow[] }> {\n const records: UsageRecord[] = [];\n const quota: CostQuotaWindow[] = [];\n const sessionId = basename(filePath, \".jsonl\");\n let currentProjectPath = \"unknown\";\n let currentProjectName = \"unknown\";\n let currentModel = \"gpt-5-codex\";\n let previous = emptyTokens();\n\n const rl = createInterface({\n input: createReadStream(filePath, { encoding: \"utf-8\" }),\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n let event: any;\n try {\n event = JSON.parse(line);\n } catch {\n continue;\n }\n\n const timestamp = event.timestamp ? new Date(event.timestamp) : new Date(0);\n\n if (event.type === \"turn_context\" && event.payload) {\n if (typeof event.payload.cwd === \"string\") {\n currentProjectPath = event.payload.cwd;\n currentProjectName = basename(currentProjectPath);\n }\n if (typeof event.payload.model === \"string\") {\n currentModel = event.payload.model;\n }\n continue;\n }\n\n if (event.type !== \"event_msg\" || event.payload?.type !== \"token_count\") continue;\n\n quota.push(...extractCodexQuota(event.payload.rate_limits, timestamp));\n\n const usage = event.payload.info?.total_token_usage as CodexTokenUsage | undefined;\n if (!usage) continue;\n\n const current = normalizeCodexTokens(usage);\n const delta = diffTokens(current, previous);\n previous = maxTokens(previous, current);\n\n if (delta.totalTokens <= 0) continue;\n\n records.push({\n provider: \"codex\",\n billingMode: \"oauth_subscription\",\n timestamp,\n sessionId,\n projectName: currentProjectName,\n projectPath: currentProjectPath,\n model: currentModel,\n tokens: delta,\n apiCostUSD: computeCodexApiCostUSD(currentModel, delta),\n subscriptionCredits: computeCodexSubscriptionCredits(currentModel, delta),\n });\n }\n\n return { records, quota };\n}\n\nasync function listCodexSessionFiles(root: string, includeArchived: boolean): Promise {\n const out: string[] = [];\n\n async function walk(dir: string) {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const path = join(dir, entry.name);\n if (entry.isDirectory()) await walk(path);\n else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) out.push(path);\n }\n }\n\n await walk(root);\n if (includeArchived) await walk(getCodexArchivedSessionsDir());\n return out;\n}\n\nfunction claudeSessionToRecord(session: Session): UsageRecord {\n return {\n provider: \"claude_code\",\n billingMode: \"api\",\n timestamp: session.updatedAt,\n sessionId: session.id,\n projectName: session.projectName,\n projectPath: session.projectPath,\n model: session.meta.models[0] ?? \"unknown\",\n tokens: emptyTokens(),\n apiCostUSD: session.meta.totalCostUSD,\n subscriptionCredits: 0,\n };\n}\n\nfunction extractCodexQuota(rateLimits: any, timestamp: Date): CostQuotaWindow[] {\n const windows: CostQuotaWindow[] = [];\n for (const name of [\"primary\", \"secondary\"] as const) {\n const value = rateLimits?.[name] as CodexRateLimitWindow | undefined;\n if (!value || typeof value.used_percent !== \"number\" || typeof value.window_minutes !== \"number\") continue;\n windows.push({\n provider: \"codex\",\n name,\n observedAt: timestamp.toISOString(),\n usedPercent: clampPercent(value.used_percent),\n remainingPercent: clampPercent(100 - value.used_percent),\n windowMinutes: value.window_minutes,\n resetsAt: typeof value.resets_at === \"number\" ? new Date(value.resets_at * 1000).toISOString() : null,\n source: \"local_log\",\n });\n }\n return windows.sort((a, b) => timestamp.getTime() - timestamp.getTime() || a.name.localeCompare(b.name));\n}\n\nfunction getProviderSummary(map: Map, provider: CostProvider): CostProviderSummary {\n const existing = map.get(provider);\n if (existing) return existing;\n const created: CostProviderSummary = {\n provider,\n billingModes: [],\n today: emptyCostTotals(),\n week: emptyCostTotals(),\n allTime: emptyCostTotals(),\n quota: [],\n };\n map.set(provider, created);\n return created;\n}\n\nfunction getProjectSummary(map: Map, name: string, path: string): CostProjectSummary {\n const key = `${name}\\0${path}`;\n const existing = map.get(key);\n if (existing) return existing;\n const created: CostProjectSummary = {\n projectName: name,\n projectPath: path,\n providers: [],\n today: emptyCostTotals(),\n week: emptyCostTotals(),\n allTime: emptyCostTotals(),\n };\n map.set(key, created);\n return created;\n}\n\nfunction latestQuotaForProvider(quota: CostQuotaWindow[], provider: CostProvider): CostQuotaWindow[] {\n const byName = new Map();\n for (const item of quota.filter((q) => q.provider === provider)) {\n const existing = byName.get(item.name);\n if (!existing || new Date(item.observedAt).getTime() >= new Date(existing.observedAt).getTime()) {\n byName.set(item.name, item);\n }\n }\n return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction roundReportTotals(value: T): T {\n value.today = roundTotals(value.today);\n value.week = roundTotals(value.week);\n value.allTime = roundTotals(value.allTime);\n return value;\n}\n\nfunction roundTotals(totals: CostPeriodTotals): CostPeriodTotals {\n return {\n ...totals,\n apiCostUSD: roundMoney(totals.apiCostUSD),\n subscriptionCredits: roundMoney(totals.subscriptionCredits),\n };\n}\n\nfunction normalizeCodexTokens(usage: CodexTokenUsage): CostTokenTotals {\n return {\n inputTokens: usage.input_tokens ?? 0,\n cachedInputTokens: usage.cached_input_tokens ?? 0,\n outputTokens: usage.output_tokens ?? 0,\n reasoningOutputTokens: usage.reasoning_output_tokens ?? 0,\n totalTokens: usage.total_tokens ?? 0,\n };\n}\n\nfunction emptyTokens(): CostTokenTotals {\n return {\n inputTokens: 0,\n cachedInputTokens: 0,\n outputTokens: 0,\n reasoningOutputTokens: 0,\n totalTokens: 0,\n };\n}\n\nfunction diffTokens(current: CostTokenTotals, previous: CostTokenTotals): CostTokenTotals {\n return {\n inputTokens: Math.max(0, current.inputTokens - previous.inputTokens),\n cachedInputTokens: Math.max(0, current.cachedInputTokens - previous.cachedInputTokens),\n outputTokens: Math.max(0, current.outputTokens - previous.outputTokens),\n reasoningOutputTokens: Math.max(0, current.reasoningOutputTokens - previous.reasoningOutputTokens),\n totalTokens: Math.max(0, current.totalTokens - previous.totalTokens),\n };\n}\n\nfunction maxTokens(a: CostTokenTotals, b: CostTokenTotals): CostTokenTotals {\n return {\n inputTokens: Math.max(a.inputTokens, b.inputTokens),\n cachedInputTokens: Math.max(a.cachedInputTokens, b.cachedInputTokens),\n outputTokens: Math.max(a.outputTokens, b.outputTokens),\n reasoningOutputTokens: Math.max(a.reasoningOutputTokens, b.reasoningOutputTokens),\n totalTokens: Math.max(a.totalTokens, b.totalTokens),\n };\n}\n\nfunction findRate(model: string, table: Record) {\n const normalized = model.toLowerCase();\n for (const [key, rate] of Object.entries(table).sort((a, b) => b[0].length - a[0].length)) {\n if (normalized.includes(key)) return rate;\n }\n return table[\"gpt-5-codex\"] ?? table[\"gpt-5.1-codex\"];\n}\n\nfunction pricedTotal(tokens: CostTokenTotals, rate: { input: number; cachedInput: number; output: number }): number {\n const perM = 1_000_000;\n return (\n (tokens.inputTokens * rate.input) / perM +\n (tokens.cachedInputTokens * rate.cachedInput) / perM +\n (tokens.outputTokens * rate.output) / perM\n );\n}\n\nfunction clampPercent(value: number): number {\n return Math.min(100, Math.max(0, value));\n}\n\nfunction roundMoney(value: number): number {\n return Math.round(value * 1_000_000) / 1_000_000;\n}\n","import { readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { homedir } from \"os\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { readStatsCache, writeStatsCache, isCacheFresh } from \"../../core/cache.js\";\nimport { discoverTodayStats } from \"../../core/fast-discovery.js\";\nimport type { StatsCache } from \"../../core/types.js\";\nimport dayjs from \"dayjs\";\n\ninterface StatuslineOptions {\n cache?: boolean;\n}\n\ninterface StdinSession {\n context_window?: {\n used_percentage?: number;\n used_tokens?: number;\n total_tokens?: number;\n };\n model?: string;\n turn_number?: number;\n session_id?: string;\n}\n\nexport async function statuslineCommand(options: StatuslineOptions): Promise {\n const { config } = ensureInit();\n const useCache = options.cache !== false;\n\n // 1. Read stdin if piped (non-blocking, 50ms timeout)\n const stdinData = process.stdin.isTTY ? null : await readStdinWithTimeout(50);\n\n // 2. Read cache\n let cache = useCache ? readStatsCache() : null;\n\n // 3. If cache fresh → use directly\n if (cache && useCache && isCacheFresh(cache)) {\n process.stdout.write(formatStatusLine(cache, stdinData));\n return;\n }\n\n // 4. If stale/missing → fast-discovery → update cache\n try {\n const todayStats = await discoverTodayStats(config.claudeDir);\n const now = dayjs();\n cache = {\n timestamp: now.toISOString(),\n todayDate: now.format(\"YYYY-MM-DD\"),\n today: todayStats,\n allTime: cache?.allTime ?? { sessions: 0, costUSD: 0, projects: 0 },\n };\n writeStatsCache(cache);\n } catch {\n if (!cache) {\n process.stdout.write(\"DevLog: scanning...\");\n return;\n }\n }\n\n // 5. Format and output\n process.stdout.write(formatStatusLine(cache!, stdinData));\n}\n\nasync function readStdinWithTimeout(ms: number): Promise {\n return Promise.race([\n new Promise((resolve) => {\n let data = \"\";\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.on(\"data\", (chunk) => { data += chunk; });\n process.stdin.on(\"end\", () => {\n try {\n resolve(JSON.parse(data) as StdinSession);\n } catch {\n resolve(null);\n }\n });\n process.stdin.resume();\n }),\n new Promise((resolve) => setTimeout(() => resolve(null), ms)),\n ]);\n}\n\nfunction readAgentState(): string {\n const statusFile = join(homedir(), \".claude-status\");\n try {\n const raw = readFileSync(statusFile, \"utf-8\");\n const match = raw.match(/\"state\":\"([^\"]+)\"/);\n const tsMatch = raw.match(/\"ts\":(\\d+)/);\n if (!match) return \"idle\";\n\n // Stale check: >30s old → idle\n if (tsMatch) {\n const age = Math.floor(Date.now() / 1000) - Number(tsMatch[1]);\n if (age > 30) return \"idle\";\n }\n return match[1];\n } catch {\n return \"idle\";\n }\n}\n\nfunction stateIndicator(state: string): string {\n switch (state) {\n case \"running\": return \"\\u26A1\"; // ⚡\n case \"done\": return \"\\u2713\"; // ✓\n case \"error\": return \"\\u2717\"; // ✗\n default: return \"\\u25CB\"; // ○\n }\n}\n\nfunction formatStatusLine(cache: StatsCache, stdinData: StdinSession | null): string {\n const parts: string[] = [];\n\n // Agent state indicator (from hooks)\n const state = readAgentState();\n parts.push(stateIndicator(state));\n\n // Context window from Claude Code stdin\n if (stdinData?.context_window?.used_percentage != null) {\n parts.push(`ctx ${stdinData.context_window.used_percentage}%`);\n }\n\n // Today stats — cost is the hero number, visually emphasized\n if (cache.today.sessions > 0) {\n const sessionWord = cache.today.sessions === 1 ? \"session\" : \"sessions\";\n parts.push(`\\u3010${formatCost(cache.today.costUSD)}\\u3011today \\u00B7 ${cache.today.sessions} ${sessionWord}`);\n } else {\n parts.push(\"No sessions today\");\n }\n\n // All-time total\n if (cache.allTime.costUSD > 0) {\n parts.push(`${formatCost(cache.allTime.costUSD)} total`);\n }\n\n return parts.join(\" \\u00B7 \");\n}\n\nfunction formatCost(usd: number): string {\n if (usd < 0.01) return `$${usd.toFixed(3)}`;\n if (usd < 1) return `$${usd.toFixed(2)}`;\n if (usd >= 1000) return `$${usd.toLocaleString(\"en-US\", { maximumFractionDigits: 0 })}`;\n return `$${usd.toFixed(2)}`;\n}\n","import { readdir, stat } from \"fs/promises\";\nimport { join } from \"path\";\nimport dayjs from \"dayjs\";\nimport type { StatsCache } from \"./types\";\nimport { decodePath, getProjectName } from \"./paths\";\nimport { scanSession } from \"./parser\";\n\n/**\n * Fast discovery: only scan JSONL files modified today.\n * Reduces scan set from 2000+ to ~10-50 files for <300ms response.\n */\nexport async function discoverTodayStats(\n claudeDir: string\n): Promise {\n const todayMidnight = dayjs().startOf(\"day\").valueOf();\n\n const result: StatsCache[\"today\"] = {\n sessions: 0,\n costUSD: 0,\n messages: 0,\n toolCalls: 0,\n filesTouched: 0,\n projects: [],\n };\n\n const fileSet = new Set();\n const projectSet = new Set();\n\n let entries;\n try {\n entries = await readdir(claudeDir, { withFileTypes: true });\n } catch {\n return result;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const projectDir = join(claudeDir, entry.name);\n const decodedPath = decodePath(entry.name);\n const projectName = getProjectName(decodedPath);\n\n let files;\n try {\n files = await readdir(projectDir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const file of files) {\n if (!file.isFile() || !file.name.endsWith(\".jsonl\")) continue;\n\n const filePath = join(projectDir, file.name);\n try {\n const fileStat = await stat(filePath);\n // Skip files not modified today\n if (fileStat.mtimeMs < todayMidnight) continue;\n\n const meta = await scanSession(filePath);\n\n // Only count if session actually has today activity\n const lastActivity = meta.lastActivity.getTime();\n if (lastActivity < todayMidnight) continue;\n\n result.sessions++;\n result.costUSD += meta.totalCostUSD;\n result.messages += meta.messageCount;\n result.toolCalls += meta.toolCalls;\n for (const f of meta.filesReferenced) fileSet.add(f);\n projectSet.add(projectName);\n } catch {\n continue;\n }\n }\n }\n\n result.filesTouched = fileSet.size;\n result.projects = [...projectSet];\n\n return result;\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, chmodSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { homedir } from \"os\";\nimport { execFileSync } from \"child_process\";\nimport { fileURLToPath } from \"url\";\nimport chalk from \"chalk\";\nimport { ensureInit } from \"../../core/config.js\";\nimport { discoverProjects, computeStats } from \"../../core/discovery.js\";\nimport { updateCacheFromStats } from \"../../core/cache.js\";\n\ninterface Hook {\n type: string;\n command: string;\n}\n\nfunction makeHookCommand(state: string): string {\n return `bash -c 'echo \"{\\\\\"state\\\\\":\\\\\"${state}\\\\\",\\\\\"ts\\\\\":$(date +%s)}\" > ~/.claude-status.tmp && mv ~/.claude-status.tmp ~/.claude-status'`;\n}\n\nfunction generateTmuxScript(devlogBin: string): string {\n return `#!/usr/bin/env bash\nset -euo pipefail\nSTATUS_FILE=\"$HOME/.claude-status\"\nSTALE_THRESHOLD=30\nDEVLOG_BIN=\"${devlogBin}\"\n\nstate=\"idle\"\nif [[ -f \"$STATUS_FILE\" ]]; then\n raw=$(cat \"$STATUS_FILE\" 2>/dev/null || echo '{}')\n state=$(echo \"$raw\" | grep -o '\"state\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4)\n ts=$(echo \"$raw\" | grep -o '\"ts\":[0-9]*' | head -1 | cut -d: -f2)\n state=\"\\${state:-idle}\"\n if [[ -n \"$ts\" ]]; then\n now=$(date +%s)\n age=$(( now - ts ))\n if (( age > STALE_THRESHOLD )); then\n state=\"idle\"\n fi\n fi\nfi\n\ncost_line=$(\"$DEVLOG_BIN\" statusline < /dev/null 2>/dev/null || echo \"\")\n\ncost_color=\"colour82\"\nif [[ \"$cost_line\" =~ \\\\$([0-9,]+\\\\.?[0-9]*) ]]; then\n amount=\"\\${BASH_REMATCH[1]//,/}\"\n cents=$(echo \"$amount\" | awk '{printf \"%d\", $1 * 100}')\n if (( cents >= 1000 )); then\n cost_color=\"colour196\"\n elif (( cents >= 100 )); then\n cost_color=\"colour226\"\n fi\nfi\n\ncase \"$state\" in\n running) indicator=\"#[fg=colour82,bold]\\u26A1#[default]\" ;;\n done) indicator=\"#[fg=colour65]\\u2713#[default]\" ;;\n error) indicator=\"#[fg=colour196]\\u2717#[default]\" ;;\n *) indicator=\"#[fg=colour243]\\u25CB#[default]\" ;;\nesac\n\nif [[ -n \"$cost_line\" ]]; then\n echo \"#[fg=\\${cost_color}]\\${cost_line}#[default] \\${indicator}\"\nelse\n echo \"\\${indicator}\"\nfi\n`;\n}\n\nconst TMUX_COMMENT = \"# DevLog status bar\";\n\nexport async function setupStatuslineCommand(): Promise {\n const { config } = ensureInit();\n\n // 1. Find devlog binary path\n let devlogBin = \"devlog\";\n try {\n devlogBin = execFileSync(\"which\", [\"devlog\"], { encoding: \"utf-8\" }).trim();\n } catch {\n // Fall back\n }\n\n // ── Claude Code: statusLine + hooks ───────────────────\n const claudeSettingsPath = join(homedir(), \".claude\", \"settings.json\");\n let settings: Record = {};\n if (existsSync(claudeSettingsPath)) {\n try {\n settings = JSON.parse(readFileSync(claudeSettingsPath, \"utf-8\"));\n } catch {\n settings = {};\n }\n }\n\n settings.statusLine = {\n type: \"command\",\n command: `${devlogBin} statusline`,\n };\n\n const hooks = ((settings.hooks as Record) ?? {}) as Record;\n for (const [event, state] of [[\"PreToolUse\", \"running\"], [\"PostToolUse\", \"done\"], [\"Stop\", \"idle\"]] as const) {\n const existing = Array.isArray(hooks[event]) ? hooks[event] : [];\n const filtered = existing.filter((h) => !h.command?.includes(\".claude-status\"));\n filtered.push({ type: \"command\", command: makeHookCommand(state) });\n hooks[event] = filtered;\n }\n settings.hooks = hooks;\n\n mkdirSync(dirname(claudeSettingsPath), { recursive: true });\n writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + \"\\n\", \"utf-8\");\n\n console.log();\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(\" Claude Code status line + hooks configured\"));\n\n // ── tmux: install script + auto-configure ─────────────\n const binDir = join(homedir(), \".devlog\", \"bin\");\n const scriptDest = join(binDir, \"tmux-claude-status.sh\");\n mkdirSync(binDir, { recursive: true });\n\n // Copy source script or generate inline\n const thisFile = fileURLToPath(import.meta.url);\n const scriptSrc = join(dirname(thisFile), \"..\", \"..\", \"scripts\", \"tmux-claude-status.sh\");\n\n if (existsSync(scriptSrc)) {\n copyFileSync(scriptSrc, scriptDest);\n } else {\n writeFileSync(scriptDest, generateTmuxScript(devlogBin), \"utf-8\");\n }\n chmodSync(scriptDest, 0o755);\n\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(\" tmux status script installed\"));\n\n // Auto-configure ~/.tmux.conf\n const tmuxConfPath = join(homedir(), \".tmux.conf\");\n let tmuxConf = \"\";\n if (existsSync(tmuxConfPath)) {\n tmuxConf = readFileSync(tmuxConfPath, \"utf-8\");\n }\n\n if (!tmuxConf.includes(\"tmux-claude-status.sh\")) {\n // Append DevLog tmux config\n const snippet = [\n \"\",\n TMUX_COMMENT,\n \"set -g status-interval 1\",\n `set -g status-right '#(${scriptDest})'`,\n \"\",\n ].join(\"\\n\");\n\n writeFileSync(tmuxConfPath, tmuxConf + snippet, \"utf-8\");\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(\" tmux.conf configured\"));\n\n // Try to reload tmux if running\n try {\n execFileSync(\"tmux\", [\"source-file\", tmuxConfPath], { stdio: \"ignore\" });\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(\" tmux reloaded\"));\n } catch {\n // tmux not running — that's fine\n }\n } else {\n console.log(chalk.dim(\" \\u2713 tmux.conf already configured\"));\n }\n\n // ── Warm cache ────────────────────────────────────────\n console.log();\n console.log(chalk.dim(\" Warming cache...\"));\n try {\n const projects = await discoverProjects(config.claudeDir);\n if (projects.length > 0) {\n updateCacheFromStats(computeStats(projects));\n }\n console.log(chalk.dim(\" Cache ready.\"));\n } catch {\n console.log(chalk.dim(\" Cache will be built on first use.\"));\n }\n\n console.log();\n console.log(chalk.white(\" Restart Claude Code to see status bar data.\"));\n console.log(chalk.white(\" tmux users: cost data with color highlights in status bar.\"));\n console.log();\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, chmodSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { homedir } from \"os\";\nimport { execFileSync } from \"child_process\";\nimport { fileURLToPath } from \"url\";\nimport chalk from \"chalk\";\n\ninterface Hook {\n type: string;\n command: string;\n}\n\ninterface ClaudeSettings {\n hooks?: {\n PreToolUse?: Hook[];\n PostToolUse?: Hook[];\n Stop?: Hook[];\n [key: string]: Hook[] | undefined;\n };\n [key: string]: unknown;\n}\n\nfunction makeHookCommand(state: string): string {\n return `bash -c 'echo \"{\\\\\"state\\\\\":\\\\\"${state}\\\\\",\\\\\"ts\\\\\":$(date +%s)}\" > ~/.claude-status.tmp && mv ~/.claude-status.tmp ~/.claude-status'`;\n}\n\nfunction removeExistingDevlogHooks(hooks: Hook[]): Hook[] {\n return hooks.filter((h) => !h.command.includes(\".claude-status\"));\n}\n\nfunction generateTmuxScript(devlogBin: string): string {\n return `#!/usr/bin/env bash\n# tmux-claude-status.sh — called by tmux status-right every 1s\n# Reads agent state from ~/.claude-status and cost from devlog statusline\n\nset -euo pipefail\n\nSTATUS_FILE=\"$HOME/.claude-status\"\nSTALE_THRESHOLD=30 # seconds — treat as idle if older\nDEVLOG_BIN=\"${devlogBin}\"\n\n# ── Read agent state ──────────────────────────────────────\nstate=\"idle\"\nif [[ -f \"$STATUS_FILE\" ]]; then\n raw=$(cat \"$STATUS_FILE\" 2>/dev/null || echo '{}')\n state=$(echo \"$raw\" | grep -o '\"state\":\"[^\"]*\"' | head -1 | cut -d'\"' -f4)\n ts=$(echo \"$raw\" | grep -o '\"ts\":[0-9]*' | head -1 | cut -d: -f2)\n state=\"\\${state:-idle}\"\n\n # Stale check: if timestamp is older than threshold, force idle\n if [[ -n \"$ts\" ]]; then\n now=$(date +%s)\n age=$(( now - ts ))\n if (( age > STALE_THRESHOLD )); then\n state=\"idle\"\n fi\n fi\nfi\n\n# ── Read cost data ────────────────────────────────────────\ncost_line=$(\"$DEVLOG_BIN\" statusline < /dev/null 2>/dev/null || echo \"\")\n\n# ── Render ────────────────────────────────────────────────\n# Cost color tiers: extract dollar amount for coloring\ncost_color=\"colour82\" # green default\nif [[ \"$cost_line\" =~ \\\\$([0-9,]+\\\\.?[0-9]*) ]]; then\n amount=\"\\${BASH_REMATCH[1]//,/}\"\n # Compare as integer cents to avoid bash float issues\n cents=$(echo \"$amount\" | awk '{printf \"%d\", $1 * 100}')\n if (( cents >= 1000 )); then\n cost_color=\"colour196\" # red: >$10\n elif (( cents >= 100 )); then\n cost_color=\"colour226\" # yellow: $1-10\n fi\nfi\n\n# State indicator\ncase \"$state\" in\n running) indicator=\"#[fg=colour82,bold]⚡#[default]\" ;;\n done) indicator=\"#[fg=colour65]✓#[default]\" ;;\n error) indicator=\"#[fg=colour196]✗#[default]\" ;;\n *) indicator=\"#[fg=colour243]○#[default]\" ;;\nesac\n\n# Final output\nif [[ -n \"$cost_line\" ]]; then\n echo \"#[fg=\\${cost_color}]\\${cost_line}#[default] \\${indicator}\"\nelse\n echo \"\\${indicator}\"\nfi\n`;\n}\n\nexport async function setupTmuxCommand(): Promise {\n // 1. Find devlog binary path\n let devlogBin = \"devlog\";\n try {\n devlogBin = execFileSync(\"which\", [\"devlog\"], { encoding: \"utf-8\" }).trim();\n } catch {\n // Fall back to \"devlog\" and hope it's in PATH\n }\n\n // ── Step 1: Install Claude Code hooks into ~/.claude/settings.json ──\n const claudeSettingsPath = join(homedir(), \".claude\", \"settings.json\");\n let settings: ClaudeSettings = {};\n if (existsSync(claudeSettingsPath)) {\n try {\n settings = JSON.parse(readFileSync(claudeSettingsPath, \"utf-8\"));\n } catch {\n settings = {};\n }\n }\n\n // Ensure hooks structure exists\n if (!settings.hooks) {\n settings.hooks = {};\n }\n\n // Remove existing devlog hooks (idempotent), then add new ones\n const preToolUse = removeExistingDevlogHooks(settings.hooks.PreToolUse ?? []);\n preToolUse.push({ type: \"command\", command: makeHookCommand(\"running\") });\n settings.hooks.PreToolUse = preToolUse;\n\n const postToolUse = removeExistingDevlogHooks(settings.hooks.PostToolUse ?? []);\n postToolUse.push({ type: \"command\", command: makeHookCommand(\"done\") });\n settings.hooks.PostToolUse = postToolUse;\n\n const stop = removeExistingDevlogHooks(settings.hooks.Stop ?? []);\n stop.push({ type: \"command\", command: makeHookCommand(\"idle\") });\n settings.hooks.Stop = stop;\n\n mkdirSync(dirname(claudeSettingsPath), { recursive: true });\n writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + \"\\n\", \"utf-8\");\n\n console.log();\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(\" Claude Code hooks installed\"));\n\n // ── Step 2: Install tmux-claude-status.sh to ~/.devlog/bin/ ──\n const destDir = join(homedir(), \".devlog\", \"bin\");\n const destPath = join(destDir, \"tmux-claude-status.sh\");\n mkdirSync(destDir, { recursive: true });\n\n // Resolve the source script relative to this file (dist/commands/setup-tmux.js)\n const thisFile = fileURLToPath(import.meta.url);\n const srcPath = join(dirname(thisFile), \"..\", \"..\", \"scripts\", \"tmux-claude-status.sh\");\n\n if (existsSync(srcPath)) {\n copyFileSync(srcPath, destPath);\n } else {\n // Fallback: generate the script inline with hardcoded DEVLOG_BIN\n writeFileSync(destPath, generateTmuxScript(devlogBin), \"utf-8\");\n }\n chmodSync(destPath, 0o755);\n\n console.log(chalk.green(\" \\u2713\") + chalk.bold.white(` tmux script installed to ${destPath}`));\n\n // ── Step 3: Print tmux config snippet ──\n console.log();\n console.log(chalk.bold.white(\" Add this to your ~/.tmux.conf:\"));\n console.log();\n console.log(chalk.cyan(\" set -g status-interval 1\"));\n console.log(chalk.cyan(\" set -g status-right '#(~/.devlog/bin/tmux-claude-status.sh)'\"));\n console.log();\n console.log(chalk.bold.white(\" Then reload tmux:\"));\n console.log();\n console.log(chalk.cyan(\" tmux source-file ~/.tmux.conf\"));\n console.log();\n}\n","import { execFile, type ChildProcess } from \"child_process\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport type { GlobalOptions } from \"../../core/types.js\";\n\nexport async function serveCommand(\n options: { port?: string },\n globalOpts: GlobalOptions\n): Promise {\n const port = options.port ?? \"3333\";\n const projectRoot = path.resolve(import.meta.dirname, \"..\", \"..\", \"..\");\n\n // Check if Next.js source exists (running from repo vs npm install)\n const nextConfigPath = path.join(projectRoot, \"next.config.ts\");\n const fs = await import(\"fs\");\n if (!fs.existsSync(nextConfigPath)) {\n console.error(chalk.red(\"\\n Dashboard requires running from the DevLog source repo.\"));\n console.error(chalk.dim(\" Clone https://github.com/moose-lab/DevLog and run from there.\\n\"));\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.bold.cyan(\" ▌\") + chalk.bold.white(\" DevLog Dashboard\"));\n console.log(chalk.dim(` Starting on port ${port}...`));\n console.log();\n\n const child: ChildProcess = execFile(\n \"npx\",\n [\"next\", \"dev\", \"--port\", port],\n { cwd: projectRoot, stdio: \"inherit\" } as any\n );\n\n // Forward signals for clean shutdown\n const cleanup = () => {\n child.kill(\"SIGTERM\");\n process.exit(0);\n };\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n // Wait for child to exit\n await new Promise((resolve, reject) => {\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) resolve();\n else reject(new Error(`Dashboard exited with code ${code}`));\n });\n child.on(\"error\", reject);\n });\n}\n"],"mappings":"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","names":["chalk","chalk","existsSync","join","join","join","existsSync","existsSync","join","dayjs","readFileSync","writeFileSync","mkdirSync","join","dayjs","join","readFileSync","mkdirSync","writeFileSync","dayjs","existsSync","chalk","existsSync","chalk","ora","chalk","config","spinner","ora","projects","stats","existsSync","chalk","ora","ora","chalk","chalk","ora","ora","chalk","chalk","ora","dayjs","isToday","dayjs","isToday","ora","chalk","totalCost","totalTools","allFiles","chalk","ora","ora","chalk","chalk","ora","dayjs","isToday","dayjs","isToday","ora","chalk","periodLabel","chalk","ora","readdir","createReadStream","createInterface","join","homedir","dayjs","join","homedir","dayjs","isToday","createInterface","createReadStream","readdir","path","chalk","ora","readFileSync","join","homedir","readdir","stat","join","dayjs","dayjs","readdir","join","stat","dayjs","join","homedir","readFileSync","existsSync","readFileSync","writeFileSync","mkdirSync","join","dirname","homedir","chalk","join","homedir","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","chalk","existsSync","readFileSync","writeFileSync","mkdirSync","copyFileSync","chmodSync","join","dirname","homedir","execFileSync","fileURLToPath","chalk","makeHookCommand","generateTmuxScript","chalk","VERSION","chalk"]} \ No newline at end of file diff --git a/docs/REVIEW-2026-06-10.md b/docs/REVIEW-2026-06-10.md new file mode 100644 index 0000000..80a444f --- /dev/null +++ b/docs/REVIEW-2026-06-10.md @@ -0,0 +1,211 @@ +# DevLog — Whole-Project Code Review & Technology Report + +**Date:** 2026-06-10 +**Branch:** `fix/devlog-2026-06-10` (cut from `origin/main` @ `879f0e2`) +**Scope:** Fine-grained, whole-repository review (not a diff) across 5 subsystems +**Method:** 5 parallel specialist reviewers (core data layer, runtime/orchestration, API security, CLI/build/CI, frontend). Several findings were empirically reproduced against `better-sqlite3` and the shipped `dist/cli.js`. + +## Baseline (verified this run) + +| Gate | Result | +|------|--------| +| `tsc --noEmit` | ✅ passes | +| `TZ=Asia/Shanghai bun run test` | ✅ 224 / 224 pass (11 s) | +| `bun install` | ✅ 670 packages | + +The green test suite is misleading: it covers cost math, schema defaults, report rendering, and pure task/auth helpers well, but has **zero coverage** for the riskiest stateful code — DB migrations, the `ProcessManager` instance lifecycle, discovery/parsing edge cases, VCC, path encode/decode, timezone boundaries, and every API route's security surface. The defects below mostly live in exactly those blind spots. + +--- + +## How to read this + +Severity reflects real-world impact, prioritized for the roadmap: + +- **🔴 Critical** — data loss, silent corruption, remote-triggerable code/command execution, or core feature non-functional. Fix before any release/publish. +- **🟠 Important** — wrong results, stuck state, resource leaks that degrade a long-running server, user-visible breakage. +- **🟡 Suggestion** — correctness/clarity/perf improvements; schedule into normal work. + +File references are clickable: [`path:line`]. + +--- + +## 🔴 Critical + +### CR-1 · `migrateTasksV2` silently nulls every session→task link on legacy DBs +[`src/core/db.ts:243`](src/core/db.ts) (the `DROP TABLE tasks` at ~`:269`), invoked from [`getDb()`](src/core/db.ts) and [`db-pool.ts:51`](src/core/db-pool.ts). + +`PRAGMA foreign_keys = ON` is set *before* migration runs. `sessions.task_id` is declared `REFERENCES tasks(id) ON DELETE SET NULL` ([`db-schema.ts:44`](src/core/db-schema.ts)). In SQLite, `DROP TABLE tasks` performs an implicit `DELETE` that **fires the FK action**, setting `task_id = NULL` on every session row. **Empirically reproduced** in this review: after the exact recreation sequence, `SELECT task_id FROM sessions` returns `null`. Triggers on every pre-V2 DB — precisely the population the migration exists to serve. The existing "preserves data" test omits a sessions table and the FK pragma, so CI can't see it. +**Fix:** wrap rebuilds in `PRAGMA foreign_keys = OFF` … recreate … `foreign_keys = ON` (the documented SQLite table-rebuild procedure); add `PRAGMA foreign_key_check`. Apply to all recreation blocks. + +### CR-2 · Dead/contradictory CHECK-widening migrations that would cascade-delete logs if they ran +[`src/core/db.ts:51`](src/core/db.ts) and [`src/core/db.ts:182`](src/core/db.ts). + +The probe `UPDATE sessions SET status='idle' WHERE status='idle'` can only throw if an `'idle'` row already exists — impossible on a legacy DB whose CHECK forbids `'idle'`. So legacy session tables are **never widened**, and the app throws `CHECK constraint failed` on the first `'idle'`/`'paused'` write. If the catch path ever did run it would: `DROP TABLE sessions` → cascade-delete `session_logs`/`session_messages` ([`db-schema.ts:85`](src/core/db-schema.ts),[`:93`](src/core/db-schema.ts)); copy only 14 of the columns (dropping `project_id`, `coding_agent_id`, …); and hit a guaranteed column-count error (`INSERT … SELECT *` of 18 cols into a 15-col table at [`db.ts:204`](src/core/db.ts)). +**Fix:** detect via `sqlite_master` SQL inspection (as `migrateTasksV2` already does), delete the dead tasks block, copy all columns, disable FKs during rebuild (CR-1). + +### CR-3 · Watchdog kills slow/healthy turns and re-executes user messages — forever, no retry cap +[`src/core/process-manager.ts:556`](src/core/process-manager.ts) (`checkHealth`), [`:639`](src/core/process-manager.ts) (`requeueLastUserMessage`), [`:1071`](src/core/process-manager.ts) (`writeMessage`). + +`writeMessage` sets `isProcessing = true` but never bumps `lastActivityAt`; only stdout handlers do. Any turn with >3 min of stdout silence (long build/test tool call, slow model) trips the watchdog: `SIGKILL` → `requeueLastUserMessage` `unshift`s the same message → respawn re-inserts it into `session_messages` and re-runs it. **No restart counter exists**, so a deterministically-slow turn is killed and re-executed every 3 minutes indefinitely — re-running an agent that may have already made partial worktree changes (duplicate side effects) and growing `session_messages` unboundedly. The watchdog also churns *idle* persistent sessions every 3 min. +**Fix:** bump `lastActivityAt` in `writeMessage` and the stderr handler; add a per-session restart counter (e.g. max 2, then fail the task); don't apply the threshold while `isProcessing` is false. + +### CR-4 · Control-plane gate responses are silently lost for every plain-stdin agent +[`src/core/process-manager.ts:1095`](src/core/process-manager.ts) (`writeMessage`), [`:1255`](src/core/process-manager.ts) (`resolveGate`), [`:1295`](src/core/process-manager.ts) (`writeGateResponse`). + +For plain-stdin agents (codex, gemini, opencode, cursor-agent, qwen, copilot), `writeMessage` closes stdin on send (`stdin.end(...)`). When the agent later emits `[DEVLOG_GATE]`, it's SIGSTOP-paused. On `resolveGate`, `writeGateResponse` hits the `writableEnded` guard and only logs "stdin no longer writable" — yet `resolveGate` **still clears the persisted gate** (`UPDATE sessions SET gate_status = NULL`, no rollback), sets `isProcessing = true`, SIGCONTs, and emits `gate_resolved` + `status: running`. The human's answer is permanently lost; the UI shows success. In the respawn branch it uses `stdin.write(... + "\n")` (never `end()`), so EOF-reading runners block forever. +**Fix:** clear `gate_status` only after a successful write; for plain-stdin runners route the answer through the normal send path (fresh process incl. prior context), or refuse `resolveGate` with an actionable error. + +### CR-5 · Path traversal in worktree creation (`name` unsanitized → `git worktree add` anywhere on disk) +[`src/app/api/worktrees/route.ts:42`](src/app/api/worktrees/route.ts) → [`src/core/worktree-manager.ts:54`](src/core/worktree-manager.ts). + +`POST /api/worktrees` reads `{ name, branch, baseBranch }` with only a falsy check, then `path.join(repoRoot, ".worktrees", name)`. `name = "../../../../tmp/pwn"` materializes a working tree (with repo files) at an attacker-chosen path. Reachable cross-origin from any webpage the user visits (no Origin check — see CR-6). `branch`/`baseBranch` starting with `-` are argument-injection into git. +**Fix:** validate `name` with `/^[A-Za-z0-9._-]{1,64}$/` and reject `..`; assert `path.relative(base, resolved)` doesn't escape; reject refs starting with `-`; pass `--` before positional paths. + +### CR-6 · No Origin/Host/CSRF validation on any state-changing endpoint +Representative: [`tasks/[id]/execute`](src/app/api/tasks/[id]/execute/route.ts), [`tasks/[id]/pr`](src/app/api/tasks/[id]/pr/route.ts), [`tasks/[id]/retry`](src/app/api/tasks/[id]/retry/route.ts), [`worktrees`](src/app/api/worktrees/route.ts), [`sessions`](src/app/api/sessions/route.ts), [`projects/active`](src/app/api/projects/active/route.ts). No `src/middleware.ts`, no CORS/header config in [`next.config.ts`](next.config.ts). + +Every mutating handler acts on body/params with no `Origin`/`Referer`/`Sec-Fetch-Site`/`Host` check. Under the stated threat model (a malicious local webpage, DNS-rebinding to `127.0.0.1`), every mutation is cross-origin reachable: create/execute tasks (spawn coding agents), delete tasks/sessions, **`git push` + `gh pr create` with the user's `gh` credentials** ([`tasks/[id]/pr`](src/app/api/tasks/[id]/pr/route.ts)), switch active project, and trigger CR-5 / CR-7. This is the single highest-leverage fix — it closes the remote trigger for most other issues. +**Fix:** add `middleware.ts` rejecting state-changing requests whose `Origin`/`Sec-Fetch-Site` isn't same-origin; validate `Host` against a `localhost`/`127.0.0.1:PORT` allowlist (defeats DNS rebinding). + +### CR-7 · Unauthenticated endpoint spawns an arbitrary local binary via request-supplied `*_BIN` +[`src/app/api/agents/connection-test/route.ts:10`](src/app/api/agents/connection-test/route.ts) → [`session-runtime-auth.ts:302`](src/core/session-runtime-auth.ts) → [`process-manager.ts:329`](src/core/process-manager.ts) (`resolveConfiguredLocalCliBinary`) → [`agent-connection-test.ts:197`](src/core/agent-connection-test.ts) (`spawn`). + +`local_cli_agent_env.{claude}.CLAUDE_BIN` (and `CODEX_BIN`/`GEMINI_BIN`/…) flow from the request body to `spawn(launch.command, …)` whenever `fs.existsSync(path)` is true. A malicious page POSTs `{"session_auth_mode":"local-cli","local_cli_agent_id":"claude","local_cli_agent_env":{"claude":{"CLAUDE_BIN":"/bin/sh"}}}` and DevLog launches it. Constrained to existing paths + agent-specific argv, but still arbitrary-existing-binary execution on an unauthenticated route. +**Fix:** only honor `*_BIN` overrides from persisted server-side settings (not transient request bodies), or restrict to an allowlisted directory; add the Origin check (CR-6). + +### CR-8 · `devlog serve` is broken in the published binary, and the committed `dist` is stale +[`src/cli/commands/serve.ts:11`](src/cli/commands/serve.ts); packaging in [`package.json:7`](package.json). + +tsup bundles to a single `dist/cli.js`, so `import.meta.dirname` is `/dist`; the three `..` in `path.resolve(import.meta.dirname, "..","..","..")` resolves *above the repo root*. **Empirically verified:** `node dist/cli.js serve` prints "Dashboard requires running from the DevLog source repo." and exits 1. Same bundled-layout bug makes [`setup-statusline.ts:120`](src/cli/commands/setup-statusline.ts) and [`setup-tmux.ts:144`](src/cli/commands/setup-tmux.ts) never find the shipped `scripts/`. Compounding it: the committed `dist/cli.js` is the npm `bin`, is weeks stale (still `VERSION = "0.4.0"` vs `package.json` `0.5.0`), `dist/` is even in `.gitignore` (force-added), and no `prepublishOnly`/`prepack` rebuilds it. Publishing today ships weeks-old code under a new version. +**Fix:** resolve the package root robustly (walk up to `package.json`); stop committing `dist/` and add `"prepublishOnly": "tsup"`, or add a CI step that rebuilds and diffs `dist/` against the commit. + +### CR-9 · `scripts/generate-test-data.ts` deletes the user's real Claude Code history — and ships in the tarball +[`scripts/generate-test-data.ts:10`](scripts/generate-test-data.ts). + +```ts +const CLAUDE_DIR = join(homedir(), ".claude", "projects"); +try { rmSync(CLAUDE_DIR, { recursive: true, force: true }); } catch {} +``` + +`rm -rf ~/.claude/projects` (all real session logs, unrecoverable) at module load — no confirmation, no guard. `package.json` `files: ["dist","scripts"]` publishes it to npm. +**Fix:** target a dedicated fixtures/temp dir; require an explicit `--force`/env guard; remove `scripts/` (or just the harness files) from the published `files`. + +--- + +## 🟠 Important + +### Correctness + +| ID | Location | Issue | +|----|----------|-------| +| IM-1 | [`parser.ts:137`](src/core/parser.ts) | **Turn duration double-counted (2×).** The `turn_duration` branch adds `durationMs`, then the generic `if (event.durationMs …)` adds the same field again. Empirically: one 5000 ms event → `totalDurationMs = 10000`. Inflates every duration stat. Fix: drop the special-cased block. | +| IM-2 | [`parser.ts:288`](src/core/parser.ts) | **Legacy string-content assistant messages silently dropped.** `if (typeof content === "string")` is nested inside `Array.isArray(content)` → unreachable. Such lines produce zero events. Fix: handle string content outside the array branch for both roles. | +| IM-3 | [`report-summary.ts:140`](src/core/report-summary.ts), [`report-evidence.ts:174`](src/core/report-evidence.ts) | **UTC-vs-local date bucketing drops up to 8 h of work.** Timestamps default to `datetime('now')` (UTC); `dateKey()` slices UTC `YYYY-MM-DD` but range boundaries use local `getFullYear/Month/Date`. In Asia/Shanghai (UTC+8) anything 00:00–08:00 local buckets into the previous day; HTML renders every timestamp 8 h early. No TZ-boundary test despite CI pinning `TZ=Asia/Shanghai`. Fix: pick one zone end-to-end. | +| IM-4 | [`discovery.ts:91`](src/core/discovery.ts) / [`parser.ts:70`](src/core/parser.ts) | **`firstActivity` fallback is dead.** Initialized to `new Date()`, so `getTime() > 0` is always true and `birthtime` fallback never runs; sessions with no timestamps report creation time = scan time (changes every scan). Fix: init to a sentinel and fall back. | +| IM-5 | [`process-manager.ts:894`](src/core/process-manager.ts) | **Stale `close` handler evicts the freshly respawned process.** Handler does `sessions.delete(sessionId)` without checking the entry still belongs to this process; after kill→respawn, the old `close` deletes the *new* `SessionProcess`, leaving an untracked live process invisible to `kill()`/watchdog. Fix: `if (sessions.get(id) === sp) delete`. | +| IM-6 | [`process-manager.ts:894`](src/core/process-manager.ts), [`task-lifecycle.ts:163`](src/core/task-lifecycle.ts) | **`exit_code` never persisted → task routing dead.** `proc.on("close", code)` never writes `code`; `sessions.exit_code` stays NULL, so `!hasChanges && exit_code !== 0` is always true (`null !== 0`) and clean exits get routed to `blocked`. Fix: persist `code`; treat NULL explicitly. | +| IM-7 | [`session-runtime-auth.ts:169`](src/core/session-runtime-auth.ts) | **Legacy `agent-api-key` sessions break on first stored-config resolution.** Persisted as `anthropic-api-key` with `legacyEnvVar` lost; next resolution treats it as browser BYOK and throws "API key is required" though preflight passed. Fix: persist `usesLegacyEnvVar ? "agent-api-key" : mode`. | +| IM-8 | [`db.ts:292`](src/core/db.ts) | **Orphan recovery strands tasks `in_progress`.** `recoverOrphanedSessions` sets sessions `failed` directly instead of `markSessionFailedAndReleaseLinkedTask`; linked tasks stay `in_progress` pointing at a dead session and can never relaunch/retry. Fix: release the linked task. | +| IM-9 | [`process-manager.ts:1255`](src/core/process-manager.ts) | **`resolveGate` ignores `ensureProcess` failure.** On respawn failure it already cleared `gate_status` and still emits `gate_resolved` + `running` while the DB row is `failed`. Fix: check the result; on failure return `{ok:false}` and don't clear the gate. | +| IM-10 | [`use-session-chat.ts:170`](src/hooks/use-session-chat.ts), [`session-chat.tsx:584`](src/components/sessions/session-chat.tsx) | **Duplicate React keys across message namespaces.** Replayed messages keep DB autoincrement ids; live messages use a module-level counter — collisions yield reconciliation bugs (messages swapped/not updating). Fix: namespace keys (`replay-`/`live-`). | +| IM-11 | [`board.tsx:55`](src/components/kanban/board.tsx), [`use-tasks.ts:93`](src/hooks/use-tasks.ts) | **Kanban drag-drop has no optimistic update + no fetch sequence guard.** Card snaps back until the POST+refetch round-trips; a 5 s poll issued before reorder commits can resolve after it and restore stale order. Fix: apply order locally in `onDragEnd`; add a monotonic sequence guard. | +| IM-12 | [`settings/page.tsx:299`](src/app/settings/page.tsx) | **Local-CLI scan POSTs on every keystroke and races.** `loadAgents` is keyed on the whole `localCliAgentEnv` object; each keystroke refires `POST /api/agents/local-cli` (a PATH scan) with no sequence guard. Fix: trigger on blur/explicit rescan; key on filtered `_BIN` values. | +| IM-13 | 8 polling hooks: [`use-daily-costs`](src/hooks/use-daily-costs.ts), [`use-devlog`](src/hooks/use-devlog.ts), [`use-locks`](src/hooks/use-locks.ts), [`use-sessions`](src/hooks/use-sessions.ts), [`use-tasks`](src/hooks/use-tasks.ts), [`use-today-stats`](src/hooks/use-today-stats.ts), [`use-vcc`](src/hooks/use-vcc.ts), [`use-worktrees`](src/hooks/use-worktrees.ts) | **Catch-less `try/finally` fetch pattern.** Network rejection → unhandled promise rejection every tick; non-OK leaves UI on stale/empty data with no error state. Fix: add `catch`, expose `error`, render it. | +| IM-14 | [`sessions/[id]/page.tsx:34`](src/app/sessions/[id]/page.tsx) | **Session detail can spin on "Loading…" forever.** 404/500/network all map to `setSession(null)` → infinite spinner while polling the dead endpoint. Fix: track not-found/error; stop polling; render a back link. | +| IM-15 | [`cli.ts:268`](src/cli/cli.ts) | **`devlog ` / `devlog help` fallthrough broken under commander 14.** Verified: `node dist/cli.js abc123def` → "too many arguments". Fix: add a `devlog ` default arg; add `help` to `KNOWN_COMMANDS`. | +| IM-16 | [`setup-tmux.ts:28`](src/cli/commands/setup-tmux.ts) | **Crashes on standard-format existing hooks.** `h.command.includes` throws when entries are `{matcher, hooks:[…]}`. Fix: optional-chain (statusline already does). | +| IM-17 | [`setup-statusline.ts:100`](src/cli/commands/setup-statusline.ts), [`setup-tmux.ts:121`](src/cli/commands/setup-tmux.ts) | **Hooks written in the wrong schema** (flat `{type,command}` vs `[{matcher,hooks:[…]}]`) → the status indicator never updates. Fix: write the matcher-wrapped structure. | +| IM-18 | [`setup-statusline.ts:86`](src/cli/commands/setup-statusline.ts), [`setup-tmux.ts:106`](src/cli/commands/setup-tmux.ts) | **Corrupt `~/.claude/settings.json` silently destroyed** — parse error → `settings = {}` → file overwritten with devlog-only object, no backup. Fix: abort on parse failure; write `.bak`. | + +### Security (beyond the Critical set) + +| ID | Location | Issue | +|----|----------|-------| +| IM-19 | [`sessions/[id]/vcc/route.ts:32`](src/app/api/sessions/[id]/vcc/route.ts) → [`vcc.ts:32`](src/core/vcc.ts) | **Path traversal via agent-controlled `claude_session_id`** (from agent stdout, unvalidated) into `getJsonlPath` + `python3` + `safeRead` → read arbitrary `.txt`/`.jsonl` files into the response. In-scope per the "malicious JSONL" threat model. Fix: validate `/^[A-Za-z0-9_-]+$/` at persist and use; assert containment. | +| IM-20 | [`tasks/[id]/route.ts:33`](src/app/api/tasks/[id]/route.ts) | **Mass-assignment + missing project scoping** on task PATCH/DELETE: values unvalidated; `session_id`/`worktree_name` repointable; GET/PATCH/DELETE not scoped by `project_id` (unlike execute/retry). Fix: validate enums/types; scope by project. | +| IM-21 | [`session-runtime-auth.ts:410`](src/core/session-runtime-auth.ts) | **SSRF allowlist bypass for local-CLI base-URL env.** Request-supplied `ANTHROPIC_BASE_URL`/`OPENAI_BASE_URL` spread into the child CLI env without `validateAgentConnectionBaseUrl` → redirects the agent's provider traffic (prompt exfiltration). Fix: validate base URLs before spreading. | +| IM-22 | [`worktree-manager.ts:47`](src/core/worktree-manager.ts) | Same root as CR-5 at the core layer — `name`/`branch` reach `git` unvalidated; option-injection via leading `-`. Fix: validate in `createWorktree` as a defense-in-depth layer independent of the route. | + +### Performance / resource leaks + +| ID | Location | Issue & impact | +|----|----------|----------------| +| IM-23 | [`discovery.ts:17`](src/core/discovery.ts) ← [`api/devlog/route.ts`](src/app/api/devlog/route.ts) | **`?command=stats` re-parses every JSONL in `~/.claude/projects` serially, every request.** No mtime memoization (the `cache.ts` stats cache is CLI-only), no concurrency; `stats`/`today` aren't even response-cached. At 2000+ sessions this is multi-second CPU+IO per dashboard poll. Also affects every CLI command (IM-29). Fix: persist per-file `SessionMeta` keyed by `(path,mtime,size)`; rescan only changed files; bounded concurrency. | +| IM-24 | [`cost-tracker.ts:346`](src/core/cost-tracker.ts), [`discovery.ts:159`](src/core/discovery.ts), [`fast-discovery.ts:61`](src/core/fast-discovery.ts) | **Claude cost is session-granular** — a week-long session's *entire* cost lands on its last-activity day; "today's cost" inflates by orders of magnitude. Claude records also hardcode `tokens: empty` + `billingMode:"api"`. Fix: emit per-message usage records from `scanSession`. | +| IM-25 | [`vcc.ts:17`](src/core/vcc.ts) | **Unbounded VCC compile cache + shared-output-file races.** Map keyed by `mtime` never evicts (each change adds a permanent MB-scale entry → steady server leak); concurrent compiles of one session write the same `.view.txt` and read each other's output; non-ENOENT failures read stale files as current. Fix: bound LRU + sweep; serialize per session; verify output mtime. | +| IM-26 | [`db-pool.ts:39`](src/core/db-pool.ts) | **LRU eviction closes connections callers may still hold** (`maxOpen` default 8) → `database connection is not open` mid-flow. Fix: `withProject(id, fn)` that pins the handle, or refcount before close. | +| IM-27 | [`use-tasks.ts:37`](src/hooks/use-tasks.ts), [`use-sessions.ts:37`](src/hooks/use-sessions.ts), [`command-stream.tsx:73`](src/components/dashboard/command-stream.tsx), [`layout.tsx:45`](src/app/layout.tsx) | **Duplicate SSE connections + overlapping polls.** Dashboard holds 3 `EventSource("/api/devlog/stream")`; tasks page 2; `/api/locks` polled every 3 s twice on every page (global `ConflictAlert` + per-page `useLocks`). Can hit the ~6-conn HTTP/1.1 per-origin cap. Fix: hoist stream + locks/tasks/sessions polls into a shared subscriber-counted singleton/context. | +| IM-28 | [`session-chat.tsx:283`](src/components/sessions/session-chat.tsx) | **Re-render storm on streaming deltas.** `messages` uncapped, `MessageBubble` unmemoized; every `text_delta` re-runs `` for *all* historical messages (many/sec). Fix: `React.memo(MessageBubble)`; window the list. | +| IM-29 | [`use-vcc.ts:20`](src/hooks/use-vcc.ts), [`sessions/[id]/page.tsx:182`](src/app/sessions/[id]/page.tsx) | **VCC fetch race + always-on hidden polling** — `SessionVcc` is CSS-hidden but mounted, refetching a full `compileSession` every 15 s even when the Process tab is never opened; grep changes race with no abort. Fix: gate mount/poll on `tab==="observe"`; add `AbortController`. | +| IM-30 | [`use-session-chat.ts:562`](src/hooks/use-session-chat.ts), [`session-chat.tsx:502`](src/components/sessions/session-chat.tsx) | **Failed sends silently lose the user's instruction** — no `res.ok` check, input cleared before awaiting, no catch. Fix: check ok, set error, restore input on failure. | + +--- + +## 🟡 Suggestions (high-value subset) + +- **Dead code:** `active-sessions-panel.tsx`, `command-stats-bar.tsx`, `parallel-worktrees-panel.tsx`, `task-quick-view.tsx`, `devlog/stats-grid.tsx` are imported nowhere; `lock-manager.ts` is a fully-built API used only by its own test while [`file-watcher.ts:58`](src/core/file-watcher.ts) is the real (diverging) writer — and it inserts `file_locks` **without `project_id`**, so rows default to `'videoclaw'` and conflict queries return empty for every other project (a latent IM-level bug). Decide one owner; delete the other. +- **Schema DDL duplicated 4×** across `db.ts`/`db-schema.ts` and already drifted (root of CR-2). Single-source it. +- **Two persistence layers coexist** — `db.ts` cwd-singleton (`${cwd}/data/devlog.db`) vs `db-pool.ts` registry + per-project DBs — and `file-watcher`/`report-summary-store`/`task-lifecycle` still use the singleton, bypassing the multi-project model. Pick one; migrate callers. +- **`db.ts` registers SIGINT/SIGTERM → `process.exit(0)` at import** ([`db.ts:333`](src/core/db.ts)), hijacking the host's shutdown and masking non-zero exit codes. Move signal handling to explicit entrypoints. +- **Report date helpers duplicated** (`report-summary.ts` vs `report-evidence.ts`, already drifted 140 vs 160 char truncation). Extract `report-dates.ts`. +- **8 near-identical polling hooks** — extract one shared fetch/poll/stream utility with error state + sequence guard + singleton SSE (fixes IM-13/27/etc. structurally). +- **`recoverOrphanedSessions` uses `process.kill(pid,0)`** — recycled PIDs keep dead sessions "running"; also match start-time/command. +- **CI hardening:** actions pinned by mutable tags (`checkout@v4`, `setup-bun@v2`, `claude-code-action@v1` — the last holds an OAuth token + `pull-requests:write`). Pin to SHAs (dependabot will bump). *Positive:* the review workflow correctly uses `pull_request`, not `pull_request_target`. +- **Repo hygiene:** `tsconfig.tsbuildinfo` and machine-specific `devlog.config.json` (`/Users/moose/...` paths, personal `activeProject`) are committed; ship `*.example.json` + gitignore. +- **`engines.node: ">=18"` is false** — `commander@14`/`ora@9` need ≥20 and `import.meta.dirname` needs ≥20.11. Bump. +- **`ChatMessage` declared twice** in [`types-dashboard.ts`](src/core/types-dashboard.ts) (merge hides it; second copy lacks `tool_calls`/`cost_usd`). Delete one. +- Smaller: `hasConflict` constant-OR bug ([`parallel-worktrees-panel.tsx:25`](src/components/dashboard/parallel-worktrees-panel.tsx)); tool-results paired by array index ([`session-chat.tsx:313`](src/components/sessions/session-chat.tsx)); `task-review-panel` field mislabel ([`:49`](src/components/kanban/task-review-panel.tsx)); random placeholder re-randomizes per render ([`launch-dialog.tsx:141`](src/components/sessions/launch-dialog.tsx)); `cost-tracker.ts:377` self-subtracting sort comparator; provider chat history resent unbounded each turn ([`api-session-runtime.ts:173`](src/core/api-session-runtime.ts)). + +--- + +## What's done well + +Genuinely solid: parser cost dedupe by `message.id` and Codex monotonic token-delta tracking; uniformly parameterized SQL (no injection found); `execFile`/`spawn` with argv arrays (no shell-string injection); provider-runtime SSRF allowlist + private-IP blocking + API-key redaction; `escapeHtml` throughout report HTML (with an XSS test); report-snapshot path-containment check; atomic tmp+rename cache writes; streaming JSONL parse (no slurp); correct `useEffect` timer/`EventSource` teardown everywhere (no leaks found); zero XSS surface (react-markdown default-safe, no `dangerouslySetInnerHTML`/`rehype-raw`); least-privilege `ci.yml`, CodeQL `security-and-quality`, dependabot for npm + actions. + +--- + +## Technology report for the development roadmap + +Sequenced so each phase unblocks the next. Rationale in brackets. + +### Phase 0 — Stop the bleeding (this branch, before any publish) +1. **Data-integrity migration fix (CR-1, CR-2).** Disable FKs during table rebuilds; replace UPDATE-probes with `sqlite_master` inspection; copy all columns; add `foreign_key_check`. *Ship-blocker: silent data loss on real user DBs.* +2. **Remove the destructive test-data script from the package + add a guard (CR-9).** *Ship-blocker: deletes user history.* +3. **Fix `serve`/packaging path resolution + stop committing stale `dist` (CR-8).** Add `prepublishOnly: tsup`; CI diff-check `dist` vs source. *The published binary is currently non-functional and stale.* + +### Phase 1 — Security boundary (one focused PR, highest leverage) +4. **`middleware.ts`: same-origin + Host-allowlist guard (CR-6).** Closes the remote trigger for CR-5/CR-7 and IM-19/20/21 in one stroke. +5. **Input validation at boundaries:** worktree `name`/`branch` (CR-5/IM-22), `claude_session_id` (IM-19), task PATCH enums + project scoping (IM-20), local-CLI base-URL/`*_BIN` restriction (CR-7/IM-21). +6. **Generic error responses** (stop echoing raw git/fs/python messages) once routes become cross-origin-readable. + +### Phase 2 — Runtime correctness & lifecycle +7. **Process-manager hardening (CR-3, CR-4, IM-5/6/9):** activity bump in `writeMessage` + restart cap; gate delivery that doesn't lie about success; persist `exit_code`; identity-checked `close` handler; release linked tasks on orphan recovery (IM-8). +8. **Single owner for process & file-lock lifecycle** — delete `lock-manager` *or* `file-watcher`'s inline path; fix the `project_id` default bug. +9. **Dedicated instance-level ProcessManager tests** with a fake `ChildProcess` (spawn→close→respawn races, watchdog requeue, kill/SIGKILL fallback, pause/resume, gate delivery). *This is the largest untested risk surface.* + +### Phase 3 — Correctness of the numbers (the product's whole point) +10. **One timezone end-to-end (IM-3)** + per-message cost/duration attribution (IM-1, IM-24). Add TZ-boundary tests (CI already pins `TZ=Asia/Shanghai` — make it meaningful). +11. **Parser coverage** for legacy/string-content events (IM-2) and `firstActivity` (IM-4); first tests for `discovery`/`parser.parseSessionFile`/`vcc`/`paths`. + +### Phase 4 — Performance & scale (as history grows) +12. **Incremental discovery cache (IM-23)** keyed by `(path,mtime,size)` with bounded concurrency — single biggest UX win for large histories; also fixes CLI cold-start (IM-29). +13. **Shared frontend data layer (IM-13/27/28/30):** one fetch/poll/stream utility (error state + sequence guard + singleton SSE), memoized chat rendering, optimistic kanban. +14. **Bound the unbounded:** VCC cache (IM-25), db-pool handles (IM-26), provider chat history, per-turn text/tool-use buffers. + +### Cross-cutting / architecture decisions to settle now +- **Consolidate the two persistence layers** (cwd-singleton vs per-project pool) before building more on either — every new feature currently has to pick one and risks divergence. +- **Move process-lifecycle/signal ownership out of the data layer** into explicit entrypoints. +- **Adopt a validation library at API boundaries** (e.g. `zod`) so route bodies are parsed, not trusted — this is the structural fix that makes Phase 1 durable rather than whack-a-mole. +- **Establish `dist`-freshness and TZ-correctness as CI gates** so the two classes of "green CI, broken artifact" bugs found here can't recur. + +--- + +### Appendix · Reviewer coverage map + +| Subsystem | Files | Critical | Important | Notable gaps | +|-----------|-------|:--------:|:---------:|--------------| +| Core data layer | `db*`, `parser`, `discovery`, `cost-*`, `report-*`, `vcc`, `cache`, `paths` | CR-1, CR-2 | IM-1..4, 23..26 | no tests for discovery/parser/vcc/paths/migrations/TZ | +| Runtime / orchestration | `process-manager`, `*-runtime`, `control-plane-*`, `task-*`, `*-manager` | CR-3, CR-4 | IM-5..9, 22 | no ProcessManager instance-lifecycle tests | +| API security | `src/app/api/**`, `lib/api-utils` | CR-5, CR-6, CR-7 | IM-19..21 | no route-level security tests | +| CLI / build / CI | `src/cli/**`, `scripts/**`, workflows, packaging | CR-8, CR-9 | IM-15..18 | CLI has no unit tests; CI verifies stale artifact | +| Frontend | `src/app/**`, `src/components/**`, `src/hooks/**` | — | IM-10..14, 27..30 | no hook/component tests beyond 2 files | diff --git a/package.json b/package.json index b4cd285..9dd66e6 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,14 @@ }, "files": [ "dist", - "scripts" + "scripts", + "!scripts/generate-test-data.ts", + "!scripts/task-launch-e2e.mjs", + "!scripts/task-launch-e2e-config.mjs" ], "scripts": { "prepare": "husky", + "prepublishOnly": "tsup", "dev": "next dev", "build": "next build", "build:cli": "tsup", diff --git a/scripts/generate-test-data.ts b/scripts/generate-test-data.ts index 00ebf18..edb600f 100644 --- a/scripts/generate-test-data.ts +++ b/scripts/generate-test-data.ts @@ -7,12 +7,8 @@ import { join } from "path"; import { homedir } from "os"; import { randomUUID } from "crypto"; -const CLAUDE_DIR = join(homedir(), ".claude", "projects"); - -// Clean previous test data -try { - rmSync(CLAUDE_DIR, { recursive: true, force: true }); -} catch {} +const REAL_CLAUDE_DIR = join(homedir(), ".claude", "projects"); +const CLAUDE_DIR = process.env.DEVLOG_TEST_DATA_DIR ?? REAL_CLAUDE_DIR; const projects = [ { @@ -343,8 +339,24 @@ function generateSessionJsonl( } function main() { + // Writing into the real Claude Code history dir is opt-in only. + if (CLAUDE_DIR === REAL_CLAUDE_DIR && !process.argv.includes("--force")) { + console.log("Refusing to write test data into your real Claude Code history dir:"); + console.log(` ${REAL_CLAUDE_DIR}`); + console.log("\nRe-run with --force to write there anyway, or set DEVLOG_TEST_DATA_DIR to a scratch dir."); + return; + } + console.log("Generating rich test data...\n"); + // Clean previous test data — only the project dirs this script generates, + // never the directory itself (it holds the user's real session history). + for (const project of projects) { + try { + rmSync(join(CLAUDE_DIR, project.encoded), { recursive: true, force: true }); + } catch {} + } + for (const project of projects) { const projectDir = join(CLAUDE_DIR, project.encoded); mkdirSync(projectDir, { recursive: true }); diff --git a/src/app/api/worktrees/route.ts b/src/app/api/worktrees/route.ts index 15c6b50..5239281 100644 --- a/src/app/api/worktrees/route.ts +++ b/src/app/api/worktrees/route.ts @@ -5,6 +5,10 @@ import { getWorktreeFilesChanged, } from "@/core/worktree-manager"; import { resolveProjectId } from "@/lib/api-utils"; +import { + validateBranchName, + validateWorktreeName, +} from "@/core/worktree-validation"; export async function GET(req: NextRequest) { try { @@ -31,13 +35,23 @@ export async function POST(req: NextRequest) { try { const { name, branch, baseBranch } = await req.json(); - if (!name || !branch) { + if (typeof name !== "string" || typeof branch !== "string" || !name || !branch) { return NextResponse.json( { error: "name and branch are required" }, { status: 400 } ); } + for (const check of [ + validateWorktreeName(name), + validateBranchName(branch), + ...(baseBranch !== undefined ? [validateBranchName(String(baseBranch))] : []), + ]) { + if (!check.ok) { + return NextResponse.json({ error: check.error }, { status: 400 }); + } + } + const projectId = resolveProjectId(req); const wt = await createWorktree(name, branch, baseBranch, projectId); return NextResponse.json(wt, { status: 201 }); diff --git a/src/cli/commands/serve.ts b/src/cli/commands/serve.ts index e96f7eb..47f726e 100644 --- a/src/cli/commands/serve.ts +++ b/src/cli/commands/serve.ts @@ -2,18 +2,18 @@ import { execFile, type ChildProcess } from "child_process"; import path from "path"; import chalk from "chalk"; import type { GlobalOptions } from "../../core/types.js"; +import { resolvePackageRoot } from "../lib/package-root.js"; export async function serveCommand( options: { port?: string }, globalOpts: GlobalOptions ): Promise { const port = options.port ?? "3333"; - const projectRoot = path.resolve(import.meta.dirname, "..", "..", ".."); + const projectRoot = resolvePackageRoot(import.meta.dirname); // Check if Next.js source exists (running from repo vs npm install) - const nextConfigPath = path.join(projectRoot, "next.config.ts"); const fs = await import("fs"); - if (!fs.existsSync(nextConfigPath)) { + if (!projectRoot || !fs.existsSync(path.join(projectRoot, "next.config.ts"))) { console.error(chalk.red("\n Dashboard requires running from the DevLog source repo.")); console.error(chalk.dim(" Clone https://github.com/moose-lab/DevLog and run from there.\n")); process.exit(1); diff --git a/src/cli/commands/setup-statusline.ts b/src/cli/commands/setup-statusline.ts index af0743c..2396f81 100644 --- a/src/cli/commands/setup-statusline.ts +++ b/src/cli/commands/setup-statusline.ts @@ -4,6 +4,7 @@ import { homedir } from "os"; import { execFileSync } from "child_process"; import { fileURLToPath } from "url"; import chalk from "chalk"; +import { resolvePackageRoot } from "../lib/package-root.js"; import { ensureInit } from "../../core/config.js"; import { discoverProjects, computeStats } from "../../core/discovery.js"; import { updateCacheFromStats } from "../../core/cache.js"; @@ -117,10 +118,12 @@ export async function setupStatuslineCommand(): Promise { mkdirSync(binDir, { recursive: true }); // Copy source script or generate inline - const thisFile = fileURLToPath(import.meta.url); - const scriptSrc = join(dirname(thisFile), "..", "..", "scripts", "tmux-claude-status.sh"); + const packageRoot = resolvePackageRoot(dirname(fileURLToPath(import.meta.url))); + const scriptSrc = packageRoot + ? join(packageRoot, "scripts", "tmux-claude-status.sh") + : null; - if (existsSync(scriptSrc)) { + if (scriptSrc && existsSync(scriptSrc)) { copyFileSync(scriptSrc, scriptDest); } else { writeFileSync(scriptDest, generateTmuxScript(devlogBin), "utf-8"); diff --git a/src/cli/commands/setup-tmux.ts b/src/cli/commands/setup-tmux.ts index 295da5f..067a8e0 100644 --- a/src/cli/commands/setup-tmux.ts +++ b/src/cli/commands/setup-tmux.ts @@ -4,6 +4,7 @@ import { homedir } from "os"; import { execFileSync } from "child_process"; import { fileURLToPath } from "url"; import chalk from "chalk"; +import { resolvePackageRoot } from "../lib/package-root.js"; interface Hook { type: string; @@ -140,11 +141,13 @@ export async function setupTmuxCommand(): Promise { const destPath = join(destDir, "tmux-claude-status.sh"); mkdirSync(destDir, { recursive: true }); - // Resolve the source script relative to this file (dist/commands/setup-tmux.js) - const thisFile = fileURLToPath(import.meta.url); - const srcPath = join(dirname(thisFile), "..", "..", "scripts", "tmux-claude-status.sh"); + // Resolve the source script from the package root (works from the bundled dist) + const packageRoot = resolvePackageRoot(dirname(fileURLToPath(import.meta.url))); + const srcPath = packageRoot + ? join(packageRoot, "scripts", "tmux-claude-status.sh") + : null; - if (existsSync(srcPath)) { + if (srcPath && existsSync(srcPath)) { copyFileSync(srcPath, destPath); } else { // Fallback: generate the script inline with hardcoded DEVLOG_BIN diff --git a/src/cli/lib/package-root.ts b/src/cli/lib/package-root.ts new file mode 100644 index 0000000..1828f4f --- /dev/null +++ b/src/cli/lib/package-root.ts @@ -0,0 +1,36 @@ +import fs from "fs"; +import path from "path"; + +const PACKAGE_NAME = "@moose-lab/devlog"; + +/** + * Resolves the DevLog package root by walking up from `startDir`. + * + * The CLI is bundled into a single dist/cli.js, so fixed `..` hops from + * import.meta.dirname land in different places depending on bundler layout + * (and currently resolve above the repo root). Anchoring on package.json + * works from the source repo, the bundled dist, and an npm installation. + * + * Prefers the directory whose package.json is named `@moose-lab/devlog`; + * falls back to the nearest package.json, or null when none exists. + */ +export function resolvePackageRoot(startDir: string): string | null { + let dir = path.resolve(startDir); + let nearest: string | null = null; + + for (;;) { + const pkgPath = path.join(dir, "package.json"); + if (fs.existsSync(pkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) as { name?: string }; + if (pkg.name === PACKAGE_NAME) return dir; + } catch { + // unreadable/invalid package.json still marks a package boundary + } + nearest ??= dir; + } + const parent = path.dirname(dir); + if (parent === dir) return nearest; + dir = parent; + } +} diff --git a/src/core/__tests__/control-plane-protocol.test.ts b/src/core/__tests__/control-plane-protocol.test.ts index 64dcd39..8467942 100644 --- a/src/core/__tests__/control-plane-protocol.test.ts +++ b/src/core/__tests__/control-plane-protocol.test.ts @@ -5,6 +5,7 @@ import { SCHEMA } from "../db-schema"; import { applyControlPlaneEvent, parseControlPlaneProtocolText, + peekControlPlaneGate, resolveControlPlaneGate, } from "../control-plane-protocol"; @@ -148,3 +149,45 @@ test("resolveControlPlaneGate clears gate state without clearing current stage", assert.equal(session.gate_status, null); assert.equal(task.gate_status, null); }); + +test("peekControlPlaneGate reads the pending gate without clearing it (CR-4)", () => { + const db = makeDb(); + db.prepare("INSERT INTO tasks (id, project_id, title) VALUES ('task-1', 'test', 'Task')").run(); + db.prepare( + "INSERT INTO sessions (id, project_id, task_id, status) VALUES ('session-1', 'test', 'task-1', 'paused')", + ).run(); + const applied = applyControlPlaneEvent( + db, + "session-1", + { + type: "gate", + question: "Continue?", + options: ["Continue"], + stage: "2/3 · approval", + }, + { + now: () => new Date("2026-06-08T08:00:00.000Z"), + createId: () => "gate-test", + }, + ); + assert.ok(applied?.gateStatus); + + // Peeking must not consume the gate — delivery may still fail, and the + // human's answer would otherwise be lost with the UI reporting success. + const peeked = peekControlPlaneGate(db, "session-1"); + assert.deepEqual(peeked?.gateStatus, applied.gateStatus); + + const session = db + .prepare("SELECT gate_status FROM sessions WHERE id = 'session-1'") + .get() as { gate_status: string | null }; + const task = db + .prepare("SELECT gate_status FROM tasks WHERE id = 'task-1'") + .get() as { gate_status: string | null }; + assert.notEqual(session.gate_status, null); + assert.notEqual(task.gate_status, null); + + // Resolving afterwards clears it exactly once. + const resolved = resolveControlPlaneGate(db, "session-1"); + assert.deepEqual(resolved?.gateStatus, applied.gateStatus); + assert.equal(peekControlPlaneGate(db, "session-1"), null); +}); diff --git a/src/core/__tests__/db-migrations.test.ts b/src/core/__tests__/db-migrations.test.ts new file mode 100644 index 0000000..13edff2 --- /dev/null +++ b/src/core/__tests__/db-migrations.test.ts @@ -0,0 +1,146 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import Database from "better-sqlite3"; +import { migrateTasksV2, migrateSessionsStatusCheck } from "../db"; + +/** + * Regression tests for CR-1 / CR-2 (REVIEW-2026-06-10): table rebuilds must + * run with foreign keys disabled, be detected via sqlite_master inspection, + * and copy every shared column. + */ + +/** Builds a pre-V2 database: old tasks CHECK, sessions with an FK to tasks. */ +function makeLegacyV1Db(): Database.Database { + const db = new Database(":memory:"); + db.pragma("journal_mode = WAL"); + db.pragma("foreign_keys = ON"); + db.exec(` + CREATE TABLE tasks ( + id TEXT PRIMARY KEY DEFAULT (hex(randomblob(8))), + project_id TEXT NOT NULL DEFAULT 'videoclaw', + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'todo' CHECK(status IN ('todo', 'in_progress', 'review', 'blocked', 'done')), + priority TEXT NOT NULL DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high', 'critical')), + worktree_name TEXT, + session_id TEXT, + sort_order INTEGER NOT NULL DEFAULT 0, + prompt TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + completed_at TEXT + ); + CREATE TABLE sessions ( + id TEXT PRIMARY KEY, + task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, + worktree_name TEXT, + status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'running', 'completed', 'failed', 'killed')), + prompt TEXT, + exit_code INTEGER, + started_at TEXT NOT NULL DEFAULT (datetime('now')), + ended_at TEXT + ); + `); + return db; +} + +test("migrateTasksV2 preserves sessions.task_id across the tasks rebuild (CR-1)", () => { + const db = makeLegacyV1Db(); + db.prepare("INSERT INTO tasks (id, title, status) VALUES ('t1', 'legacy task', 'todo')").run(); + db.prepare( + "INSERT INTO sessions (id, task_id, status) VALUES ('s1', 't1', 'completed')" + ).run(); + + migrateTasksV2(db); + + const session = db + .prepare("SELECT task_id FROM sessions WHERE id = 's1'") + .get() as { task_id: string | null }; + assert.equal(session.task_id, "t1"); + + const violations = db.prepare("PRAGMA foreign_key_check").all(); + assert.deepEqual(violations, []); + + // The rebuilt table accepts the widened status set. + db.prepare("INSERT INTO tasks (id, title, status) VALUES ('t2', 'queued', 'in_queue')").run(); + // FK enforcement is back on after the rebuild. + assert.equal(db.pragma("foreign_keys", { simple: true }), 1); +}); + +test("migrateTasksV2 keeps task data for legacy tables missing newer columns (CR-1)", () => { + const db = makeLegacyV1Db(); + db.prepare( + "INSERT INTO tasks (id, title, status, priority, prompt) VALUES ('t1', 'keep me', 'review', 'high', 'do things')" + ).run(); + + migrateTasksV2(db); + + const task = db + .prepare("SELECT title, status, priority, prompt, sandbox_iterations FROM tasks WHERE id = 't1'") + .get() as { title: string; status: string; priority: string; prompt: string; sandbox_iterations: number }; + assert.equal(task.title, "keep me"); + assert.equal(task.status, "review"); + assert.equal(task.priority, "high"); + assert.equal(task.prompt, "do things"); + assert.equal(task.sandbox_iterations, 0); +}); + +test("migrateSessionsStatusCheck widens legacy CHECK and preserves logs (CR-2)", () => { + const db = makeLegacyV1Db(); + db.exec(` + CREATE TABLE session_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE, + chunk TEXT NOT NULL, + stream TEXT NOT NULL DEFAULT 'stdout', + timestamp TEXT NOT NULL DEFAULT (datetime('now')) + ); + `); + db.prepare("INSERT INTO sessions (id, status, prompt) VALUES ('s1', 'running', 'hello')").run(); + db.prepare("INSERT INTO session_logs (session_id, chunk) VALUES ('s1', 'log line')").run(); + + // Legacy CHECK rejects 'idle' before the migration runs. + assert.throws(() => + db.prepare("UPDATE sessions SET status = 'idle' WHERE id = 's1'").run() + ); + + migrateSessionsStatusCheck(db); + + // Status CHECK is widened and prior data survived the rebuild. + db.prepare("UPDATE sessions SET status = 'idle' WHERE id = 's1'").run(); + const session = db + .prepare("SELECT status, prompt FROM sessions WHERE id = 's1'") + .get() as { status: string; prompt: string }; + assert.equal(session.status, "idle"); + assert.equal(session.prompt, "hello"); + + const logs = db.prepare("SELECT chunk FROM session_logs WHERE session_id = 's1'").all(); + assert.equal(logs.length, 1); + + const violations = db.prepare("PRAGMA foreign_key_check").all(); + assert.deepEqual(violations, []); +}); + +test("migrateSessionsStatusCheck is a no-op when the CHECK already includes idle/paused", () => { + const db = makeLegacyV1Db(); + db.exec("DROP TABLE sessions"); + db.exec(` + CREATE TABLE sessions ( + id TEXT PRIMARY KEY, + task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, + status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'running', 'idle', 'paused', 'completed', 'failed', 'killed')), + started_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + `); + db.prepare("INSERT INTO sessions (id, status) VALUES ('s1', 'idle')").run(); + const before = db + .prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'") + .get() as { sql: string }; + + migrateSessionsStatusCheck(db); + + const after = db + .prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'") + .get() as { sql: string }; + assert.equal(after.sql, before.sql); +}); diff --git a/src/core/__tests__/db-schema.test.ts b/src/core/__tests__/db-schema.test.ts index abb14a0..c9096ff 100644 --- a/src/core/__tests__/db-schema.test.ts +++ b/src/core/__tests__/db-schema.test.ts @@ -215,3 +215,27 @@ test("recoverOrphanedSessions preserves paused gated sessions", () => { assert.equal(gated.gate_status, gateStatus); assert.equal(orphaned.status, "failed"); }); + +test("recoverOrphanedSessions releases the linked in-progress task (IM-8)", () => { + const db = makeTestDb(); + db.prepare( + "INSERT INTO tasks (id, project_id, title, status, session_id) VALUES ('task-1', 'test', 'Stranded task', 'in_progress', 'dead-session')", + ).run(); + db.prepare( + "INSERT INTO sessions (id, project_id, task_id, status, pid) VALUES ('dead-session', 'test', 'task-1', 'running', 99999999)", + ).run(); + + recoverOrphanedSessions(db); + + const session = db + .prepare("SELECT status FROM sessions WHERE id = 'dead-session'") + .get() as { status: string }; + const task = db + .prepare("SELECT status, fail_reason FROM tasks WHERE id = 'task-1'") + .get() as { status: string; fail_reason: string | null }; + + assert.equal(session.status, "failed"); + // The task must leave 'in_progress' so it can be relaunched or retried. + assert.equal(task.status, "fail"); + assert.ok(task.fail_reason); +}); diff --git a/src/core/__tests__/local-cli-env-hardening.test.ts b/src/core/__tests__/local-cli-env-hardening.test.ts new file mode 100644 index 0000000..1fbb7c3 --- /dev/null +++ b/src/core/__tests__/local-cli-env-hardening.test.ts @@ -0,0 +1,73 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { resolveSessionRuntimeAuthConfig } from "../session-runtime-auth"; + +/** + * Regression tests for CR-7 / IM-21 (REVIEW-2026-06-10): request bodies could + * point *_BIN at any existing binary (POST {"CLAUDE_BIN":"/bin/sh"} spawned a + * shell on an unauthenticated route) and spread unvalidated *_BASE_URL values + * into the child CLI env (SSRF / provider-traffic redirection). + */ + +test("*_BIN overrides not named after the agent binary are dropped (CR-7)", () => { + const config = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "claude", + local_cli_agent_env: { CLAUDE_BIN: "/bin/sh" }, + }); + assert.equal(config.localCliAgentEnv.CLAUDE_BIN, undefined); +}); + +test("*_BIN overrides pointing at the agent binary are kept", () => { + const claude = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "claude", + local_cli_agent_env: { CLAUDE_BIN: "/opt/tools/claude" }, + }); + assert.equal(claude.localCliAgentEnv.CLAUDE_BIN, "/opt/tools/claude"); + + const codex = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "codex", + local_cli_agent_env: { CODEX_BIN: "C:\\tools\\codex.exe" }, + }); + assert.equal(codex.localCliAgentEnv.CODEX_BIN, "C:\\tools\\codex.exe"); +}); + +test("base URLs failing connection validation are dropped (IM-21)", () => { + const metadata = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "codex", + local_cli_agent_env: { OPENAI_BASE_URL: "http://169.254.169.254/v1" }, + }); + assert.equal(metadata.localCliAgentEnv.OPENAI_BASE_URL, undefined); + + const privateIp = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "claude", + local_cli_agent_env: { ANTHROPIC_BASE_URL: "http://10.0.0.5" }, + }); + assert.equal(privateIp.localCliAgentEnv.ANTHROPIC_BASE_URL, undefined); +}); + +test("valid proxy and loopback base URLs are kept", () => { + const proxy = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "codex", + local_cli_agent_env: { OPENAI_BASE_URL: "https://gateway.example.com/v1" }, + }); + assert.equal( + proxy.localCliAgentEnv.OPENAI_BASE_URL, + "https://gateway.example.com/v1" + ); + + const loopback = resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "claude", + local_cli_agent_env: { ANTHROPIC_BASE_URL: "http://127.0.0.1:8080" }, + }); + assert.equal( + loopback.localCliAgentEnv.ANTHROPIC_BASE_URL, + "http://127.0.0.1:8080" + ); +}); diff --git a/src/core/__tests__/package-root.test.ts b/src/core/__tests__/package-root.test.ts new file mode 100644 index 0000000..8a0c69c --- /dev/null +++ b/src/core/__tests__/package-root.test.ts @@ -0,0 +1,58 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { resolvePackageRoot } from "../../cli/lib/package-root"; + +/** + * Regression tests for CR-8 (REVIEW-2026-06-10): the bundled dist/cli.js used + * fixed `..` hops from import.meta.dirname, which resolve above the repo root + * once tsup flattens the output. Resolution must anchor on package.json. + */ + +function makeTree(): string { + return mkdtempSync(join(tmpdir(), "devlog-pkg-root-")); +} + +test("resolvePackageRoot finds the devlog package root from a nested dir", () => { + const root = makeTree(); + try { + writeFileSync(join(root, "package.json"), JSON.stringify({ name: "@moose-lab/devlog" })); + const nested = join(root, "dist", "deep"); + mkdirSync(nested, { recursive: true }); + + assert.equal(resolvePackageRoot(nested), root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("resolvePackageRoot prefers the devlog package over a nearer foreign package.json", () => { + const root = makeTree(); + try { + writeFileSync(join(root, "package.json"), JSON.stringify({ name: "@moose-lab/devlog" })); + const sub = join(root, "vendor"); + mkdirSync(sub, { recursive: true }); + writeFileSync(join(sub, "package.json"), JSON.stringify({ name: "something-else" })); + const nested = join(sub, "deep"); + mkdirSync(nested, { recursive: true }); + + assert.equal(resolvePackageRoot(nested), root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("resolvePackageRoot falls back to the nearest package.json when no devlog root exists", () => { + const root = makeTree(); + try { + writeFileSync(join(root, "package.json"), JSON.stringify({ name: "some-host-app" })); + const nested = join(root, "node_modules", "x"); + mkdirSync(nested, { recursive: true }); + + assert.equal(resolvePackageRoot(nested), root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/src/core/__tests__/process-manager-health.test.ts b/src/core/__tests__/process-manager-health.test.ts index 2ac8129..d2444c4 100644 --- a/src/core/__tests__/process-manager-health.test.ts +++ b/src/core/__tests__/process-manager-health.test.ts @@ -1,8 +1,13 @@ import { test } from "node:test"; import assert from "node:assert/strict"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { + MAX_WATCHDOG_RESTARTS, SESSION_UNRESPONSIVE_MS, buildClaudeProcessArgs, + canDeliverGateResponse, buildLocalCliProcessLaunch, needsBrowserApiKeyForWatchdogRestart, parseClaudeBinaryPath, @@ -65,6 +70,57 @@ test("shouldRestartUnresponsiveSession only restarts live stale processes", () = ); }); +test("idle persistent sessions are never watchdog-restarted (CR-3)", () => { + const now = Date.parse("2026-05-22T12:00:00.000Z"); + + // Stale but not processing: a persistent session waiting for the next + // user message must not be churned every interval. + assert.equal( + shouldRestartUnresponsiveSession({ + lastActivityAt: now - SESSION_UNRESPONSIVE_MS - 1, + now, + killed: false, + isProcessing: false, + }), + false, + ); + + assert.equal( + shouldRestartUnresponsiveSession({ + lastActivityAt: now - SESSION_UNRESPONSIVE_MS - 1, + now, + killed: false, + isProcessing: true, + }), + true, + ); +}); + +test("watchdog restart budget is bounded (CR-3)", () => { + assert.equal(MAX_WATCHDOG_RESTARTS >= 1 && MAX_WATCHDOG_RESTARTS <= 3, true); +}); + +test("gate responses are only deliverable while agent stdin is open (CR-4)", () => { + const withStdin = (stdin: { destroyed: boolean; writableEnded: boolean } | null) => ({ + proc: { stdin }, + }); + + assert.equal( + canDeliverGateResponse(withStdin({ destroyed: false, writableEnded: false })), + true, + ); + // Plain-stdin runners: stdin.end() was called on the original send. + assert.equal( + canDeliverGateResponse(withStdin({ destroyed: false, writableEnded: true })), + false, + ); + assert.equal( + canDeliverGateResponse(withStdin({ destroyed: true, writableEnded: false })), + false, + ); + assert.equal(canDeliverGateResponse(withStdin(null)), false); +}); + test("parseClaudeBinaryPath ignores shell alias descriptions", () => { // parseClaudeBinaryPath uses fs.existsSync to filter out junk lines that // happen to start with "/" (e.g. shell-alias descriptions). The candidate @@ -236,6 +292,35 @@ test("buildLocalCliProcessLaunch builds Codex stdin runner args", () => { }); test("buildLocalCliProcessLaunch honors selected CLI binary overrides", () => { + const dir = mkdtempSync(join(tmpdir(), "devlog-bin-override-")); + const codexBin = join(dir, "codex"); + try { + writeFileSync(codexBin, "#!/bin/sh\n", { mode: 0o755 }); + const launch = buildLocalCliProcessLaunch( + resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "codex", + local_cli_agent_env: { + CODEX_BIN: codexBin, + }, + }), + null, + ["Read"], + "/repo", + () => null, + ); + + assert.equal(launch.ok, true); + if (!launch.ok) return; + assert.equal(launch.command, codexBin); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); + +test("buildLocalCliProcessLaunch ignores overrides pointing at foreign binaries (CR-7)", () => { + // process.execPath exists but is the node binary, not the agent CLI — + // exactly the arbitrary-binary gadget from the review. const launch = buildLocalCliProcessLaunch( resolveSessionRuntimeAuthConfig({ session_auth_mode: "local-cli", @@ -250,9 +335,9 @@ test("buildLocalCliProcessLaunch honors selected CLI binary overrides", () => { () => null, ); - assert.equal(launch.ok, true); - if (!launch.ok) return; - assert.equal(launch.command, process.execPath); + assert.equal(launch.ok, false); + if (launch.ok) return; + assert.match(launch.error, /not installed or not on PATH/i); }); test("buildLocalCliProcessLaunch rejects missing CLI binary overrides", () => { @@ -295,23 +380,30 @@ test("validateSessionRuntimeProcessLaunch rejects missing CLI binary overrides b }); test("buildLocalCliProcessLaunch honors Claude binary overrides", () => { - const launch = buildLocalCliProcessLaunch( - resolveSessionRuntimeAuthConfig({ - session_auth_mode: "local-cli", - local_cli_agent_id: "claude", - local_cli_agent_env: { - CLAUDE_BIN: process.execPath, - }, - }), - null, - ["Read"], - "/repo", - () => null, - ); + const dir = mkdtempSync(join(tmpdir(), "devlog-bin-override-")); + const claudeBin = join(dir, "claude"); + try { + writeFileSync(claudeBin, "#!/bin/sh\n", { mode: 0o755 }); + const launch = buildLocalCliProcessLaunch( + resolveSessionRuntimeAuthConfig({ + session_auth_mode: "local-cli", + local_cli_agent_id: "claude", + local_cli_agent_env: { + CLAUDE_BIN: claudeBin, + }, + }), + null, + ["Read"], + "/repo", + () => null, + ); - assert.equal(launch.ok, true); - if (!launch.ok) return; - assert.equal(launch.command, process.execPath); + assert.equal(launch.ok, true); + if (!launch.ok) return; + assert.equal(launch.command, claudeBin); + } finally { + rmSync(dir, { recursive: true, force: true }); + } }); test("buildLocalCliProcessLaunch passes custom model ids to supported runners", () => { diff --git a/src/core/__tests__/request-origin-guard.test.ts b/src/core/__tests__/request-origin-guard.test.ts new file mode 100644 index 0000000..fcba60c --- /dev/null +++ b/src/core/__tests__/request-origin-guard.test.ts @@ -0,0 +1,101 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { evaluateApiRequest } from "../../lib/request-origin-guard"; + +/** + * Regression tests for CR-6 (REVIEW-2026-06-10): every state-changing API + * route was reachable cross-origin (CSRF from any webpage, DNS rebinding to + * 127.0.0.1). The guard must reject non-local Hosts and cross-origin writes. + */ + +test("blocks mutating requests with a cross-origin Origin header", () => { + const verdict = evaluateApiRequest({ + method: "POST", + origin: "https://evil.example", + secFetchSite: null, + host: "localhost:3333", + }); + assert.equal(verdict.allowed, false); +}); + +test("blocks mutating requests marked cross-site by Sec-Fetch-Site", () => { + const verdict = evaluateApiRequest({ + method: "DELETE", + origin: null, + secFetchSite: "cross-site", + host: "127.0.0.1:3333", + }); + assert.equal(verdict.allowed, false); +}); + +test("blocks any request whose Host is not loopback (DNS rebinding)", () => { + const verdict = evaluateApiRequest({ + method: "GET", + origin: null, + secFetchSite: null, + host: "devlog.attacker.example:3333", + }); + assert.equal(verdict.allowed, false); +}); + +test("blocks mutating requests with an opaque 'null' Origin", () => { + const verdict = evaluateApiRequest({ + method: "POST", + origin: "null", + secFetchSite: null, + host: "localhost:3333", + }); + assert.equal(verdict.allowed, false); +}); + +test("allows same-origin browser mutations", () => { + const verdict = evaluateApiRequest({ + method: "POST", + origin: "http://localhost:3333", + secFetchSite: "same-origin", + host: "localhost:3333", + }); + assert.equal(verdict.allowed, true); +}); + +test("allows local reads and headerless CLI clients", () => { + assert.equal( + evaluateApiRequest({ + method: "GET", + origin: null, + secFetchSite: null, + host: "127.0.0.1:3000", + }).allowed, + true + ); + // curl-style request: no Origin, no Sec-Fetch-Site + assert.equal( + evaluateApiRequest({ + method: "POST", + origin: null, + secFetchSite: null, + host: "localhost:3333", + }).allowed, + true + ); +}); + +test("allows IPv6 loopback hosts", () => { + const verdict = evaluateApiRequest({ + method: "POST", + origin: "http://[::1]:3333", + secFetchSite: "same-origin", + host: "[::1]:3333", + }); + assert.equal(verdict.allowed, true); +}); + +test("blocks requests with a missing Host header", () => { + const verdict = evaluateApiRequest({ + method: "GET", + origin: null, + secFetchSite: null, + host: null, + }); + assert.equal(verdict.allowed, false); +}); diff --git a/src/core/__tests__/task-lifecycle.test.ts b/src/core/__tests__/task-lifecycle.test.ts index a2b1315..3ff61c7 100644 --- a/src/core/__tests__/task-lifecycle.test.ts +++ b/src/core/__tests__/task-lifecycle.test.ts @@ -2,6 +2,7 @@ import { test } from "node:test"; import assert from "node:assert/strict"; import { makeTestDb } from "./test-helpers"; import { + isFailedSessionExit, markSessionFailedAndReleaseLinkedTask, validateTaskSessionLaunch, } from "../task-lifecycle"; @@ -121,3 +122,12 @@ test("session launch validation only allows executable tasks in the current proj }, ); }); + +test("only a recorded non-zero exit code counts as a failed session exit (IM-6)", () => { + // NULL was previously read as failure, routing every clean exit to blocked + // because exit_code was never persisted. + assert.equal(isFailedSessionExit(null), false); + assert.equal(isFailedSessionExit(0), false); + assert.equal(isFailedSessionExit(1), true); + assert.equal(isFailedSessionExit(137), true); +}); diff --git a/src/core/__tests__/vcc-session-id.test.ts b/src/core/__tests__/vcc-session-id.test.ts new file mode 100644 index 0000000..8974275 --- /dev/null +++ b/src/core/__tests__/vcc-session-id.test.ts @@ -0,0 +1,45 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { compileSession, isValidClaudeSessionId } from "../vcc"; + +/** + * Regression tests for IM-19 (REVIEW-2026-06-10): claude_session_id is parsed + * from agent stdout (attacker-influenced under the malicious-JSONL threat + * model) and flowed unvalidated into a filesystem path, python3 argv, and + * safeRead — letting a traversal id read arbitrary .txt/.jsonl files into the + * API response. + */ + +test("isValidClaudeSessionId accepts UUID-style and slug ids", () => { + for (const id of [ + "0199b1c4-f7a2-7e11-8b3a-1c2d3e4f5a6b", + "abc123", + "session_42", + "A-b_C-1", + ]) { + assert.equal(isValidClaudeSessionId(id), true, id); + } +}); + +test("isValidClaudeSessionId rejects traversal and separator ids", () => { + for (const id of [ + "../../../etc/passwd", + "..", + "a/b", + "a\\b", + "id.jsonl", + "", + " ", + "a".repeat(129), + "id\n", + ]) { + assert.equal(isValidClaudeSessionId(id), false, JSON.stringify(id)); + } +}); + +test("compileSession refuses invalid session ids before touching the filesystem", async () => { + await assert.rejects( + () => compileSession("../../../../tmp/evil", "/some/project"), + /Invalid Claude session id/ + ); +}); diff --git a/src/core/__tests__/worktree-validation.test.ts b/src/core/__tests__/worktree-validation.test.ts new file mode 100644 index 0000000..5d71133 --- /dev/null +++ b/src/core/__tests__/worktree-validation.test.ts @@ -0,0 +1,62 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { + validateWorktreeName, + validateBranchName, +} from "../worktree-validation"; + +/** + * Regression tests for CR-5 / IM-22 (REVIEW-2026-06-10): POST /api/worktrees + * passed `name` into path.join with only a falsy check — a traversal name + * materialized a working tree at an attacker-chosen path — and refs starting + * with '-' were git argument injection. + */ + +test("validateWorktreeName accepts simple names", () => { + for (const name of ["feature-x", "fix_123", "a", "release.2026", "A-b.c_d"]) { + assert.equal(validateWorktreeName(name).ok, true, name); + } +}); + +test("validateWorktreeName rejects traversal and injection attempts", () => { + for (const name of [ + "../../../../tmp/pwn", + "..", + "a/../b", + "nested/dir", + "-rf", + ".hidden", + "", + " ", + "a".repeat(65), + "name with spaces", + "tilde~", + ]) { + assert.equal(validateWorktreeName(name).ok, false, JSON.stringify(name)); + } +}); + +test("validateBranchName accepts normal git branch refs", () => { + for (const branch of ["main", "feature/login", "fix/devlog-2026-06-10", "v1.2.3", "user/feat_x"]) { + assert.equal(validateBranchName(branch).ok, true, branch); + } +}); + +test("validateBranchName rejects option injection and invalid refs", () => { + for (const branch of [ + "-D", + "--force", + "-b evil", + "..", + "a..b", + ".hidden", + "branch.lock", + "has space", + "", + "a".repeat(201), + "ends/", + "double//slash", + ]) { + assert.equal(validateBranchName(branch).ok, false, JSON.stringify(branch)); + } +}); diff --git a/src/core/agent-settings.ts b/src/core/agent-settings.ts index 1aa2e81..a53a349 100644 --- a/src/core/agent-settings.ts +++ b/src/core/agent-settings.ts @@ -687,6 +687,19 @@ function normalizeLocalCliAgentModels( return choices; } +/** + * A *_BIN override is spawned by DevLog, so it may only point at a file + * actually named like the agent's binary (plus an optional extension). + * Without this, any request body could launch an arbitrary existing binary + * such as /bin/sh (CR-7). + */ +function isAllowedBinOverride(agentId: string, value: string): boolean { + const bin = LOCAL_CLI_AGENT_DEFINITIONS.find((agent) => agent.id === agentId)?.bin; + if (!bin) return false; + const basename = value.split(/[\\/]/).pop() ?? ""; + return basename === bin || basename.startsWith(`${bin}.`); +} + export function normalizeLocalCliAgentEnv(value: unknown): LocalCliAgentEnv { if (!isRecord(value)) { return {}; @@ -700,15 +713,23 @@ export function normalizeLocalCliAgentEnv(value: unknown): LocalCliAgentEnv { const allowed = LOCAL_CLI_AGENT_ENV_KEYS.get(agentId); if (!allowed) continue; + const binEnvKey = LOCAL_CLI_AGENT_DEFINITIONS.find( + (agent) => agent.id === agentId, + )?.binEnvKey; + const agentEnv: Record = {}; for (const [envKey, rawValue] of Object.entries(rawEnv)) { if (!allowed.has(envKey) || typeof rawValue !== "string") { continue; } const trimmed = rawValue.trim().slice(0, MAX_LOCAL_CLI_ENV_VALUE_LENGTH); - if (trimmed) { - agentEnv[envKey] = trimmed; + if (!trimmed) { + continue; + } + if (envKey === binEnvKey && !isAllowedBinOverride(agentId, trimmed)) { + continue; } + agentEnv[envKey] = trimmed; } if (Object.keys(agentEnv).length > 0) { result[agentId] = agentEnv; diff --git a/src/core/control-plane-protocol.ts b/src/core/control-plane-protocol.ts index d292ef9..5acee42 100644 --- a/src/core/control-plane-protocol.ts +++ b/src/core/control-plane-protocol.ts @@ -117,7 +117,13 @@ export function applyControlPlaneEvent( }; } -export function resolveControlPlaneGate( +/** + * Reads the pending gate without clearing it. Delivery code must peek first + * and only clear (resolve) once the response has actually been handed to the + * agent process — clearing eagerly loses the human's answer when delivery + * fails (CR-4/IM-9). + */ +export function peekControlPlaneGate( db: Database.Database, sessionId: string, ): ResolvedControlPlaneGate | null { @@ -131,13 +137,6 @@ export function resolveControlPlaneGate( const gateStatus = parseGateStatus(session.gate_status); if (!gateStatus) return null; - db.prepare("UPDATE sessions SET gate_status = NULL WHERE id = ?").run(sessionId); - if (session.task_id) { - db.prepare( - "UPDATE tasks SET gate_status = NULL, updated_at = datetime('now') WHERE id = ?", - ).run(session.task_id); - } - return { sessionId, taskId: session.task_id, @@ -146,6 +145,23 @@ export function resolveControlPlaneGate( }; } +export function resolveControlPlaneGate( + db: Database.Database, + sessionId: string, +): ResolvedControlPlaneGate | null { + const peeked = peekControlPlaneGate(db, sessionId); + if (!peeked) return null; + + db.prepare("UPDATE sessions SET gate_status = NULL WHERE id = ?").run(sessionId); + if (peeked.taskId) { + db.prepare( + "UPDATE tasks SET gate_status = NULL, updated_at = datetime('now') WHERE id = ?", + ).run(peeked.taskId); + } + + return peeked; +} + function parseProtocolMarker( markerType: string, rawJson: string, diff --git a/src/core/db-schema.ts b/src/core/db-schema.ts index 367b6ad..1fb317a 100644 --- a/src/core/db-schema.ts +++ b/src/core/db-schema.ts @@ -16,8 +16,9 @@ import { DEFAULT_LOCAL_CLI_REASONING, } from "./local-cli-agent-definitions"; -export const SCHEMA = ` -CREATE TABLE IF NOT EXISTS tasks ( +/** Canonical tasks table DDL; pass a different name when rebuilding in place. */ +export function tasksTableDdl(tableName = "tasks"): string { + return `CREATE TABLE IF NOT EXISTS ${tableName} ( id TEXT PRIMARY KEY DEFAULT (hex(randomblob(8))), project_id TEXT NOT NULL DEFAULT 'videoclaw', title TEXT NOT NULL, @@ -36,9 +37,12 @@ CREATE TABLE IF NOT EXISTS tasks ( created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), completed_at TEXT -); +);`; +} -CREATE TABLE IF NOT EXISTS sessions ( +/** Canonical sessions table DDL; pass a different name when rebuilding in place. */ +export function sessionsTableDdl(tableName = "sessions"): string { + return `CREATE TABLE IF NOT EXISTS ${tableName} ( id TEXT PRIMARY KEY, project_id TEXT NOT NULL DEFAULT 'videoclaw', task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, @@ -67,7 +71,13 @@ CREATE TABLE IF NOT EXISTS sessions ( log_path TEXT, started_at TEXT NOT NULL DEFAULT (datetime('now')), ended_at TEXT -); +);`; +} + +export const SCHEMA = ` +${tasksTableDdl()} + +${sessionsTableDdl()} CREATE TABLE IF NOT EXISTS file_locks ( id TEXT PRIMARY KEY DEFAULT (hex(randomblob(8))), diff --git a/src/core/db.ts b/src/core/db.ts index 8df8394..6ac5d0a 100644 --- a/src/core/db.ts +++ b/src/core/db.ts @@ -1,7 +1,10 @@ import Database from "better-sqlite3"; import path from "path"; import fs from "fs"; -import { SCHEMA } from "./db-schema"; +import { SCHEMA, sessionsTableDdl, tasksTableDdl } from "./db-schema"; +// Circular at module level (task-lifecycle uses getDb), but both sides only +// touch each other's exports inside function bodies, which ESM resolves. +import { markSessionFailedAndReleaseLinkedTask } from "./task-lifecycle"; import { DEFAULT_AGENT_TEAM_ID, DEFAULT_CODING_AGENT_ID, @@ -46,53 +49,9 @@ export function getDb(): Database.Database { // Column already exists } - // Migrate: update CHECK constraint to include 'idle' status - // SQLite can't alter CHECK constraints, so recreate the table if needed - try { - _db.exec("UPDATE sessions SET status = 'idle' WHERE status = 'idle'"); - } catch { - // CHECK constraint fails — need to recreate table - _db.exec(` - CREATE TABLE IF NOT EXISTS sessions_new ( - id TEXT PRIMARY KEY, - task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL, - worktree_name TEXT, worktree_path TEXT, branch_name TEXT, - pid INTEGER, - status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','running','idle','paused','completed','failed','killed')), - claude_command TEXT, claude_session_id TEXT, - coding_agent_id TEXT NOT NULL DEFAULT '${DEFAULT_CODING_AGENT_ID}', - agent_team_id TEXT NOT NULL DEFAULT '${DEFAULT_AGENT_TEAM_ID}', - session_auth_mode TEXT NOT NULL DEFAULT '${DEFAULT_SESSION_AUTH_MODE}', - agent_api_key_env_var TEXT, - local_cli_agent_id TEXT NOT NULL DEFAULT '${DEFAULT_LOCAL_CLI_AGENT_ID}', - agent_model TEXT NOT NULL DEFAULT '${DEFAULT_AGENT_MODEL}', - agent_reasoning TEXT NOT NULL DEFAULT '${DEFAULT_LOCAL_CLI_REASONING}', - agent_api_protocol TEXT NOT NULL DEFAULT '${DEFAULT_API_PROTOCOL}', - agent_api_version TEXT NOT NULL DEFAULT '', - agent_base_url TEXT NOT NULL DEFAULT '${DEFAULT_API_BASE_URL}', - agent_max_tokens INTEGER NOT NULL DEFAULT ${DEFAULT_API_MAX_TOKENS}, - current_stage TEXT, - gate_status TEXT, - prompt TEXT, - exit_code INTEGER, log_path TEXT, - started_at TEXT NOT NULL DEFAULT (datetime('now')), - ended_at TEXT - ); - INSERT OR IGNORE INTO sessions_new ( - id, task_id, worktree_name, worktree_path, branch_name, pid, status, - claude_command, claude_session_id, prompt, exit_code, log_path, - started_at, ended_at - ) - SELECT id, task_id, worktree_name, worktree_path, branch_name, pid, status, - claude_command, claude_session_id, prompt, exit_code, log_path, - started_at, ended_at - FROM sessions; - DROP TABLE sessions; - ALTER TABLE sessions_new RENAME TO sessions; - CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status); - CREATE INDEX IF NOT EXISTS idx_sessions_task ON sessions(task_id); - `); - } + // Migrate: widen the sessions status CHECK ('idle'/'paused') when a legacy + // table is detected. SQLite can't alter CHECK constraints, so this rebuilds. + migrateSessionsStatusCheck(_db); // Migrate: add project_id columns if missing for (const table of ["tasks", "sessions", "file_locks"]) { @@ -176,39 +135,6 @@ export function getDb(): Database.Database { } catch { // Column already exists } - migrateControlPlaneColumns(_db); - - // Migrate: update tasks CHECK constraint to include 'review' and 'blocked' - try { - _db.exec("UPDATE tasks SET status = 'review' WHERE status = 'review'"); - } catch { - // CHECK constraint fails — recreate table with expanded constraint - _db.exec(` - CREATE TABLE IF NOT EXISTS tasks_new ( - id TEXT PRIMARY KEY DEFAULT (hex(randomblob(8))), - project_id TEXT NOT NULL DEFAULT 'videoclaw', - title TEXT NOT NULL, - description TEXT, - status TEXT NOT NULL DEFAULT 'todo' CHECK(status IN ('todo', 'in_progress', 'review', 'blocked', 'done')), - priority TEXT NOT NULL DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high', 'critical')), - worktree_name TEXT, - session_id TEXT, - sort_order INTEGER NOT NULL DEFAULT 0, - prompt TEXT, - current_stage TEXT, - gate_status TEXT, - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')), - completed_at TEXT - ); - INSERT OR IGNORE INTO tasks_new SELECT * FROM tasks; - DROP TABLE tasks; - ALTER TABLE tasks_new RENAME TO tasks; - CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); - CREATE INDEX IF NOT EXISTS idx_tasks_sort ON tasks(status, sort_order); - CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id, status); - `); - } // Recover orphaned sessions on first access if (!_recovered) { @@ -242,36 +168,86 @@ export function migrateTasksV2(db: Database.Database): void { // Status CHECK widening: SQLite cannot ALTER CHECK; recreate the table only if old CHECK is detected. const stmt = db.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='tasks'").get() as { sql: string } | undefined; if (stmt && (!stmt.sql.includes("'in_queue'") || !stmt.sql.includes("'fail'"))) { - db.exec(` - CREATE TABLE tasks_new ( - id TEXT PRIMARY KEY DEFAULT (hex(randomblob(8))), - project_id TEXT NOT NULL DEFAULT 'videoclaw', - title TEXT NOT NULL, - description TEXT, - status TEXT NOT NULL DEFAULT 'todo' CHECK(status IN ('todo', 'in_queue', 'in_progress', 'review', 'blocked', 'fail', 'done')), - priority TEXT NOT NULL DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high', 'critical')), - worktree_name TEXT, - session_id TEXT, - sort_order INTEGER NOT NULL DEFAULT 0, - prompt TEXT, - blocked_by TEXT, - sandbox_iterations INTEGER NOT NULL DEFAULT 0, - fail_reason TEXT, - current_stage TEXT, - gate_status TEXT, - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')), - completed_at TEXT + rebuildTable( + db, + "tasks", + tasksTableDdl("tasks_new"), + `CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); + CREATE INDEX IF NOT EXISTS idx_tasks_sort ON tasks(status, sort_order); + CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id, status);` + ); + } +} + +/** + * Widens the sessions status CHECK to include 'idle'/'paused' on legacy DBs. + * Detection is via sqlite_master SQL inspection — an UPDATE probe can never + * trip the old constraint because forbidden values can't already be stored. + */ +export function migrateSessionsStatusCheck(db: Database.Database): void { + const stmt = db + .prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'") + .get() as { sql: string } | undefined; + if (!stmt || (stmt.sql.includes("'idle'") && stmt.sql.includes("'paused'"))) { + return; + } + rebuildTable( + db, + "sessions", + sessionsTableDdl("sessions_new"), + `CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status); + CREATE INDEX IF NOT EXISTS idx_sessions_task ON sessions(task_id); + CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id, status);` + ); +} + +/** + * Rebuilds a table following SQLite's documented table-rebuild procedure: + * foreign keys OFF for the duration, copy the intersection of old/new columns + * (legacy tables may lack newer ones), then verify with foreign_key_check. + * With FKs left ON, `DROP TABLE` fires ON DELETE actions in referencing + * tables — e.g. nulling every sessions.task_id (CR-1) or cascade-deleting + * session logs (CR-2). + */ +function rebuildTable( + db: Database.Database, + table: string, + createNewSql: string, + postSql = "" +): void { + const fkWasOn = db.pragma("foreign_keys", { simple: true }) === 1; + db.pragma("foreign_keys = OFF"); + try { + db.exec(`DROP TABLE IF EXISTS ${table}_new`); + db.exec(createNewSql); + const columnsOf = (name: string) => + (db.prepare(`PRAGMA table_info(${name})`).all() as Array<{ name: string }>).map( + (col) => col.name ); - INSERT INTO tasks_new (id, project_id, title, description, status, priority, worktree_name, session_id, sort_order, prompt, blocked_by, sandbox_iterations, fail_reason, current_stage, gate_status, created_at, updated_at, completed_at) - SELECT id, project_id, title, description, status, priority, worktree_name, session_id, sort_order, prompt, blocked_by, sandbox_iterations, fail_reason, current_stage, gate_status, created_at, updated_at, completed_at - FROM tasks; - DROP TABLE tasks; - ALTER TABLE tasks_new RENAME TO tasks; - CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); - CREATE INDEX IF NOT EXISTS idx_tasks_sort ON tasks(status, sort_order); - CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id, status); + const newColumns = new Set(columnsOf(`${table}_new`)); + const shared = columnsOf(table) + .filter((col) => newColumns.has(col)) + .map((col) => `"${col}"`) + .join(", "); + db.exec(` + BEGIN; + INSERT INTO ${table}_new (${shared}) SELECT ${shared} FROM ${table}; + DROP TABLE ${table}; + ALTER TABLE ${table}_new RENAME TO ${table}; + ${postSql} + COMMIT; `); + const violations = db.prepare("PRAGMA foreign_key_check").all(); + if (violations.length > 0) { + throw new Error( + `foreign_key_check reported ${violations.length} violation(s) after rebuilding ${table}` + ); + } + } catch (err) { + if (db.inTransaction) db.exec("ROLLBACK"); + throw err; + } finally { + if (fkWasOn) db.pragma("foreign_keys = ON"); } } @@ -316,9 +292,13 @@ export function recoverOrphanedSessions(db: Database.Database): void { if (session.status === "paused" && session.gate_status) { continue; } - db.prepare( - "UPDATE sessions SET status = 'failed', ended_at = datetime('now') WHERE id = ?" - ).run(session.id); + // IM-8: release the linked task too — failing only the session left + // tasks 'in_progress' pointing at a dead session, unable to relaunch. + markSessionFailedAndReleaseLinkedTask( + db, + session.id, + "Session process was lost (server restart or crash) and could not be recovered." + ); } } } diff --git a/src/core/process-manager.ts b/src/core/process-manager.ts index 60a342e..768b2e9 100644 --- a/src/core/process-manager.ts +++ b/src/core/process-manager.ts @@ -12,6 +12,7 @@ import { import { applyControlPlaneEvent, parseControlPlaneProtocolText, + peekControlPlaneGate, resolveControlPlaneGate, type ControlPlaneProtocolEvent, type ResolvedControlPlaneGate, @@ -35,6 +36,7 @@ import { LOCAL_CLI_AGENT_DEFINITIONS, } from "./local-cli-agent-definitions"; import { resolveExecutableOnPath } from "./local-cli-agents"; +import { isValidClaudeSessionId } from "./vcc"; export function parseClaudeBinaryPath(output: string): string | null { for (const rawLine of output.split("\n")) { @@ -167,19 +169,30 @@ interface SessionProcess { export const WATCHDOG_INTERVAL_MS = 30000; export const SESSION_UNRESPONSIVE_MS = 3 * 60 * 1000; +/** Watchdog restarts per session before the turn is failed instead (CR-3). */ +export const MAX_WATCHDOG_RESTARTS = 2; export function shouldRestartUnresponsiveSession({ lastActivityAt, now, killed, paused = false, + isProcessing = true, }: { lastActivityAt: number; now: number; killed: boolean; paused?: boolean; + isProcessing?: boolean; }): boolean { - return now - lastActivityAt > SESSION_UNRESPONSIVE_MS && !killed && !paused; + // An idle persistent session has nothing to restart — only stall detection + // during an in-flight turn is meaningful (CR-3 churned idle sessions). + return ( + isProcessing && + now - lastActivityAt > SESSION_UNRESPONSIVE_MS && + !killed && + !paused + ); } export function needsBrowserApiKeyForWatchdogRestart( @@ -189,6 +202,19 @@ export function needsBrowserApiKeyForWatchdogRestart( return isProcessing && sessionAuthMode === "anthropic-api-key"; } +/** + * A gate response can only reach the agent while its stdin is still open. + * Plain-stdin runners get their stdin closed by the original send, so a + * paused process in that state can never receive the answer (CR-4). + */ +export function canDeliverGateResponse(sp: { + proc: { stdin: { destroyed: boolean; writableEnded: boolean } | null }; +}): boolean { + return Boolean( + sp.proc.stdin && !sp.proc.stdin.destroyed && !sp.proc.stdin.writableEnded, + ); +} + export function buildClaudeProcessArgs( runtimeAuthConfig: SessionRuntimeAuthConfig, claudeSessionId: string | null, @@ -528,6 +554,7 @@ class ProcessManager { private sessions = new Map(); private messageQueues = new Map(); private providerProcessing = new Set(); + private watchdogRestarts = new Map(); constructor() { const watchdog = setInterval( @@ -562,11 +589,39 @@ class ProcessManager { now, killed: sp.proc.killed, paused: sp.paused, + isProcessing: sp.isProcessing, }) ) { continue; } + const restarts = (this.watchdogRestarts.get(sessionId) ?? 0) + 1; + this.watchdogRestarts.set(sessionId, restarts); + if (restarts > MAX_WATCHDOG_RESTARTS) { + const message = `Session ${sessionId.slice(0, 8)} stayed unresponsive after ${MAX_WATCHDOG_RESTARTS} watchdog restarts. Failing the turn instead of re-executing it again.`; + this.emitSystemLog("warning", sessionId, message, "[WATCHDOG]"); + + try { + sp.proc.kill("SIGKILL"); + } catch { + // ignore + } + this.sessions.delete(sessionId); + this.messageQueues.delete(sessionId); + this.watchdogRestarts.delete(sessionId); + + try { + const db = getDb(); + markSessionFailedAndReleaseLinkedTask(db, sessionId, message); + } catch { + // ignore + } + + streamManager.emit(sessionId, { type: "error", message }); + streamManager.emit(sessionId, { type: "status", status: "failed" }); + continue; + } + const sessionAuthMode = this.getStoredSessionAuthMode(sessionId); const cannotRestartWithoutBrowserKey = needsBrowserApiKeyForWatchdogRestart(sessionAuthMode, sp.isProcessing); @@ -865,6 +920,7 @@ class ProcessManager { // Capture stderr for debugging if (proc.stderr) { proc.stderr.on("data", (chunk: Buffer) => { + sp.lastActivityAt = Date.now(); const text = chunk.toString().trim(); if (text) { // Log stderr but don't surface as errors unless critical @@ -893,7 +949,14 @@ class ProcessManager { // Handle process close after stdout/stderr have flushed. proc.on("close", (code) => { this.flushGenericOutput(sessionId, sp); - this.sessions.delete(sessionId); + + // After a kill→respawn, this close belongs to the replaced process; + // deleting unconditionally would evict the freshly respawned entry and + // leave a live process invisible to kill() and the watchdog (IM-5). + const isCurrent = this.sessions.get(sessionId) === sp; + if (isCurrent) { + this.sessions.delete(sessionId); + } this.emitSystemLog( code === 0 ? "success" : "warning", sessionId, @@ -912,6 +975,12 @@ class ProcessManager { } } + // A stale close must not touch the session's live state — the + // respawned process owns status, exit_code, and task routing now. + if (!isCurrent) { + return; + } + // If there was a turn in progress, notify about the interruption if (sp.isProcessing) { streamManager.emit(sessionId, { @@ -922,13 +991,14 @@ class ProcessManager { }); } - // Update status to idle (can spawn new process for next message) + // Update status to idle (can spawn new process for next message) and + // persist the exit code — task routing reads it on session exit (IM-6). const newStatus = "idle"; let statusUpdated = false; try { const result = db.prepare( - "UPDATE sessions SET status = ?, pid = NULL WHERE id = ? AND status NOT IN ('completed', 'failed', 'killed')" - ).run(newStatus, sessionId); + "UPDATE sessions SET status = ?, pid = NULL, exit_code = ? WHERE id = ? AND status NOT IN ('completed', 'failed', 'killed')" + ).run(newStatus, code, sessionId); statusUpdated = result.changes > 0; } catch { // ignore @@ -1085,8 +1155,11 @@ class ProcessManager { content: message, }); - // Mark as processing + // Mark as processing. The activity clock starts at send time — without + // this, a turn whose first stdout takes >3m is killed by the watchdog + // and silently re-executed (CR-3). sp.isProcessing = true; + sp.lastActivityAt = Date.now(); sp.textBuffer = ""; sp.toolCalls = []; @@ -1235,44 +1308,62 @@ class ProcessManager { } const db = getDb(); - const resolved = resolveControlPlaneGate(db, sessionId); - if (!resolved) { + const pending = peekControlPlaneGate(db, sessionId); + if (!pending) { return { ok: false, error: "no pending gate" }; } - const insertResult = db.prepare( - "INSERT INTO session_messages (session_id, role, content) VALUES (?, 'user', ?)", - ).run(sessionId, trimmed); - const messageId = Number(insertResult.lastInsertRowid); + let sp = this.sessions.get(sessionId); - streamManager.emit(sessionId, { - type: "message", - id: messageId, - role: "user", - content: trimmed, - }); + // A plain-stdin runner whose stdin was consumed by the original send can + // never read the answer — the SIGSTOPped process must be replaced with a + // fresh one rather than pretending the write succeeded (CR-4). + if (sp && !sp.proc.killed && !canDeliverGateResponse(sp)) { + try { + sp.proc.kill("SIGKILL"); + } catch { + // ignore + } + if (this.sessions.get(sessionId) === sp) { + this.sessions.delete(sessionId); + } + sp = undefined; + } - let sp = this.sessions.get(sessionId); if (!sp || sp.proc.killed) { sp = this.ensureProcess(sessionId) ?? undefined; } - if (sp && !sp.proc.killed) { - const requestId = sp.pendingPermission?.requestId ?? resolved.gateStatus.id; - sp.pendingPermission = null; - if (sp.paused) { - sp.proc.kill("SIGCONT"); - sp.paused = false; - } - sp.isProcessing = true; - this.writeGateResponse(sp, trimmed); - streamManager.emit(sessionId, { - type: "permission_resolved", - request_id: requestId, - approved: true, - }); + // IM-9: if the process could not be (re)created, keep the gate persisted + // and report failure instead of emitting a fake gate_resolved. + if (!sp || sp.proc.killed || !canDeliverGateResponse(sp)) { + return { + ok: false, + error: + "The agent process is unavailable and could not be restarted, so the gate response was not delivered. The gate is still pending — try again.", + }; } + const requestId = sp.pendingPermission?.requestId ?? pending.gateStatus.id; + sp.pendingPermission = null; + if (sp.paused) { + sp.proc.kill("SIGCONT"); + sp.paused = false; + } + + // Delivery is possible — only now clear the persisted gate and record the + // response. writeMessage persists + emits the user message and uses the + // protocol-correct write (stdin.end for plain-stdin runners, which would + // otherwise block forever waiting for EOF). + const resolved = resolveControlPlaneGate(db, sessionId) ?? pending; + this.writeMessage(sp, trimmed); + + streamManager.emit(sessionId, { + type: "permission_resolved", + request_id: requestId, + approved: true, + }); + db.prepare( "UPDATE sessions SET status = 'running' WHERE id = ? AND status = 'paused'", ).run(sessionId); @@ -1292,37 +1383,6 @@ class ProcessManager { return { ok: true }; } - private writeGateResponse(sp: SessionProcess, response: string): void { - if (!sp.proc.stdin || sp.proc.stdin.destroyed || sp.proc.stdin.writableEnded) { - this.emitSystemLog( - "warning", - sp.sessionId, - "Gate resolved, but agent stdin is no longer writable.", - ); - return; - } - - try { - if (sp.inputProtocol === "claude-stream-json") { - const inputMsg = JSON.stringify({ - type: "user", - message: { role: "user", content: response }, - session_id: sp.claudeSessionId ?? "default", - parent_tool_use_id: null, - }); - sp.proc.stdin.write(inputMsg + "\n"); - return; - } - sp.proc.stdin.write(response + "\n"); - } catch (err) { - this.emitSystemLog( - "warning", - sp.sessionId, - `Failed to write gate response: ${err instanceof Error ? err.message : String(err)}`, - ); - } - } - private handleGenericOutputChunk( sessionId: string, sp: SessionProcess, @@ -1755,8 +1815,12 @@ class ProcessManager { // System events — capture session_id if (type === "system") { - if (subtype === "init" && event.session_id) { - sp.claudeSessionId = event.session_id as string; + if ( + subtype === "init" && + typeof event.session_id === "string" && + isValidClaudeSessionId(event.session_id) + ) { + sp.claudeSessionId = event.session_id; const db = getDb(); try { db.prepare( @@ -1859,7 +1923,7 @@ class ProcessManager { if (type === "result") { const isError = event.is_error === true; const claudeSessionId = event.session_id as string | undefined; - if (claudeSessionId) { + if (claudeSessionId && isValidClaudeSessionId(claudeSessionId)) { sp.claudeSessionId = claudeSessionId; const db = getDb(); try { @@ -1891,8 +1955,9 @@ class ProcessManager { session_id: claudeSessionId, }); - // Reset turn state + // Reset turn state; a completed turn restores the watchdog budget sp.isProcessing = false; + this.watchdogRestarts.delete(sessionId); sp.textBuffer = ""; sp.toolCalls = []; diff --git a/src/core/session-runtime-auth.ts b/src/core/session-runtime-auth.ts index e4f4ea5..f8c944b 100644 --- a/src/core/session-runtime-auth.ts +++ b/src/core/session-runtime-auth.ts @@ -23,6 +23,23 @@ import { LOCAL_CLI_AGENT_DEFINITIONS, LOCAL_CLI_AGENT_IDS, } from "./local-cli-agent-definitions"; +import { validateAgentConnectionBaseUrl } from "./api-provider-runtime"; + +/** + * Local-CLI env values named *_BASE_URL redirect the agent's provider + * traffic, so they must pass the same SSRF validation as direct provider + * base URLs before they reach the child process env (IM-21). + */ +function dropInvalidBaseUrls(env: Record): Record { + const result: Record = {}; + for (const [key, value] of Object.entries(env)) { + if (key.endsWith("_BASE_URL") && validateAgentConnectionBaseUrl(value).error) { + continue; + } + result[key] = value; + } + return result; +} export type SessionRuntimeAuthMode = "local-cli" | "anthropic-api-key"; export type LegacySessionRuntimeAuthMode = "backend-oauth" | "agent-api-key"; @@ -301,11 +318,13 @@ export function resolveSessionRuntimeAuthConfig( const localCliAgent = findLocalCliAgent(localCliAgentId); const localCliAgentEnv = mode === "local-cli" - ? normalizeLocalCliAgentEnv({ - [localCliAgentId]: isRecord(input.local_cli_agent_env) - ? input.local_cli_agent_env - : {}, - })[localCliAgentId] ?? {} + ? dropInvalidBaseUrls( + normalizeLocalCliAgentEnv({ + [localCliAgentId]: isRecord(input.local_cli_agent_env) + ? input.local_cli_agent_env + : {}, + })[localCliAgentId] ?? {}, + ) : {}; const option = SESSION_RUNTIME_AUTH_OPTIONS.find((candidate) => candidate.id === mode) ?? diff --git a/src/core/task-lifecycle.ts b/src/core/task-lifecycle.ts index 8b0bf11..7d9a257 100644 --- a/src/core/task-lifecycle.ts +++ b/src/core/task-lifecycle.ts @@ -123,6 +123,15 @@ export function validateTaskSessionLaunch( return { ok: true, task }; } +/** + * exit_code semantics (IM-6): a number is a real exit status; NULL means the + * code was never recorded (signal kill, legacy row) and must not be read as + * failure — that routed every clean exit to 'blocked'. + */ +export function isFailedSessionExit(exitCode: number | null): boolean { + return typeof exitCode === "number" && exitCode !== 0; +} + export async function onSessionExit(sessionId: string): Promise { const db = getDb(); const session = db @@ -156,11 +165,16 @@ export async function onSessionExit(sessionId: string): Promise { } } + const failedExit = isFailedSessionExit(session.exit_code); + + // Clean exit without changes is deliberately left alone: the session goes + // idle and can take follow-up instructions, so the human decides whether + // the task is done — auto-routing here would close work that isn't. if (hasChanges && task.status === "in_progress") { db.prepare( "UPDATE tasks SET status = 'review', updated_at = datetime('now') WHERE id = ?" ).run(task.id); - } else if (!hasChanges && session.exit_code !== 0 && task.status === "in_progress") { + } else if (!hasChanges && failedExit && task.status === "in_progress") { db.prepare( "UPDATE tasks SET status = 'blocked', updated_at = datetime('now') WHERE id = ?" ).run(task.id); diff --git a/src/core/vcc.ts b/src/core/vcc.ts index bf9840d..508240c 100644 --- a/src/core/vcc.ts +++ b/src/core/vcc.ts @@ -1,9 +1,19 @@ import { execFile } from "child_process"; import { promisify } from "util"; import { existsSync, readFileSync, statSync } from "fs"; -import { join } from "path"; +import { isAbsolute, join, relative } from "path"; import { getClaudeProjectsDir } from "./paths"; +/** + * claude_session_id is parsed from agent stdout, so it must stay a single + * path-safe token before reaching the filesystem or python3 argv (IM-19). + */ +const CLAUDE_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/; + +export function isValidClaudeSessionId(id: string): boolean { + return CLAUDE_SESSION_ID_PATTERN.test(id); +} + const execFileAsync = promisify(execFile); export interface VccOutput { @@ -69,7 +79,15 @@ export async function compileSession( projectPath: string, grep?: string ): Promise { + if (!isValidClaudeSessionId(claudeSessionId)) { + throw new Error("Invalid Claude session id"); + } + const jsonlPath = getJsonlPath(claudeSessionId, projectPath); + const containment = relative(getClaudeProjectsDir(), jsonlPath); + if (containment.startsWith("..") || isAbsolute(containment)) { + throw new Error("Invalid Claude session id"); + } if (!existsSync(jsonlPath)) { return EMPTY; diff --git a/src/core/worktree-manager.ts b/src/core/worktree-manager.ts index e03513e..8fe4967 100644 --- a/src/core/worktree-manager.ts +++ b/src/core/worktree-manager.ts @@ -3,6 +3,7 @@ import { promisify } from "util"; import path from "path"; import type { Worktree } from "./types-dashboard"; import { getRepoRoot } from "./project-adapter"; +import { validateBranchName, validateWorktreeName } from "./worktree-validation"; const execFileAsync = promisify(execFile); @@ -50,13 +51,27 @@ export async function createWorktree( baseBranch?: string, projectId?: string ): Promise { + const nameCheck = validateWorktreeName(name); + if (!nameCheck.ok) throw new Error(nameCheck.error); + const branchCheck = validateBranchName(branch); + if (!branchCheck.ok) throw new Error(branchCheck.error); + if (baseBranch !== undefined) { + const baseCheck = validateBranchName(baseBranch); + if (!baseCheck.ok) throw new Error(baseCheck.error); + } + const repoRoot = getRepoRoot(projectId); - const worktreePath = path.join(repoRoot, ".worktrees", name); + const worktreesBase = path.join(repoRoot, ".worktrees"); + const worktreePath = path.join(worktreesBase, name); + const relative = path.relative(worktreesBase, worktreePath); + if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { + throw new Error("Invalid worktree name: resolves outside the worktrees directory"); + } if (baseBranch) { - await git(projectId, "worktree", "add", "-b", branch, worktreePath, baseBranch); + await git(projectId, "worktree", "add", "-b", branch, "--", worktreePath, baseBranch); } else { - await git(projectId, "worktree", "add", "-b", branch, worktreePath); + await git(projectId, "worktree", "add", "-b", branch, "--", worktreePath); } const worktrees = await listWorktrees(projectId); diff --git a/src/core/worktree-validation.ts b/src/core/worktree-validation.ts new file mode 100644 index 0000000..e013714 --- /dev/null +++ b/src/core/worktree-validation.ts @@ -0,0 +1,46 @@ +/** + * Input validation for worktree creation (CR-5 / IM-22). + * + * `name` becomes a filesystem path segment and `branch`/`baseBranch` become + * git argv entries, so both must be constrained before reaching path.join or + * git: traversal names escape the repo, and refs starting with '-' are read + * by git as options. + */ + +// One path segment: starts alphanumeric, no separators, no leading '.' or '-'. +const WORKTREE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/; + +// Git ref name: slash-separated segments, each starting alphanumeric. +const BRANCH_SEGMENT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/; +const MAX_BRANCH_LENGTH = 200; + +export type ValidationResult = { ok: true } | { ok: false; error: string }; + +export function validateWorktreeName(name: string): ValidationResult { + if (!WORKTREE_NAME_PATTERN.test(name) || name.includes("..")) { + return { + ok: false, + error: + "Invalid worktree name: use 1-64 letters, digits, '.', '_' or '-', starting with a letter or digit", + }; + } + return { ok: true }; +} + +export function validateBranchName(branch: string): ValidationResult { + const invalid = { + ok: false as const, + error: + "Invalid branch name: use slash-separated segments of letters, digits, '.', '_' or '-', each starting with a letter or digit", + }; + if (!branch || branch.length > MAX_BRANCH_LENGTH || branch.includes("..")) { + return invalid; + } + const segments = branch.split("/"); + for (const segment of segments) { + if (!BRANCH_SEGMENT_PATTERN.test(segment) || segment.endsWith(".lock")) { + return invalid; + } + } + return { ok: true }; +} diff --git a/src/lib/request-origin-guard.ts b/src/lib/request-origin-guard.ts new file mode 100644 index 0000000..726e555 --- /dev/null +++ b/src/lib/request-origin-guard.ts @@ -0,0 +1,67 @@ +/** + * Origin/Host guard for the local API (CR-6). + * + * DevLog binds to localhost with no auth, so the threat model is a malicious + * webpage in the user's browser: cross-origin form/fetch CSRF against + * state-changing routes, and DNS rebinding to read local data. Two checks + * close both: the Host header must be loopback for every API request, and + * mutating requests must not carry cross-origin browser markers. Requests + * without browser headers (curl, scripts) stay allowed. + */ + +const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]); + +const SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]); + +const ALLOWED_SEC_FETCH_SITES = new Set(["same-origin", "same-site", "none"]); + +export interface ApiRequestContext { + method: string; + origin: string | null; + secFetchSite: string | null; + host: string | null; +} + +export interface ApiRequestVerdict { + allowed: boolean; + reason?: string; +} + +function isLoopbackHost(hostHeader: string | null): boolean { + if (!hostHeader) return false; + try { + const { hostname } = new URL(`http://${hostHeader}`); + return LOOPBACK_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost"); + } catch { + return false; + } +} + +function isLoopbackOrigin(origin: string): boolean { + try { + const { hostname } = new URL(origin); + return LOOPBACK_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost"); + } catch { + return false; + } +} + +export function evaluateApiRequest(ctx: ApiRequestContext): ApiRequestVerdict { + if (!isLoopbackHost(ctx.host)) { + return { allowed: false, reason: "API requests must target localhost" }; + } + + if (SAFE_METHODS.has(ctx.method.toUpperCase())) { + return { allowed: true }; + } + + if (ctx.secFetchSite && !ALLOWED_SEC_FETCH_SITES.has(ctx.secFetchSite)) { + return { allowed: false, reason: "Cross-site API mutations are not allowed" }; + } + + if (ctx.origin && !isLoopbackOrigin(ctx.origin)) { + return { allowed: false, reason: "Cross-origin API mutations are not allowed" }; + } + + return { allowed: true }; +} diff --git a/src/proxy.ts b/src/proxy.ts new file mode 100644 index 0000000..f8aeb7d --- /dev/null +++ b/src/proxy.ts @@ -0,0 +1,24 @@ +import { NextRequest, NextResponse } from "next/server"; +import { evaluateApiRequest } from "@/lib/request-origin-guard"; + +export function proxy(req: NextRequest) { + const verdict = evaluateApiRequest({ + method: req.method, + origin: req.headers.get("origin"), + secFetchSite: req.headers.get("sec-fetch-site"), + host: req.headers.get("host"), + }); + + if (!verdict.allowed) { + return NextResponse.json( + { error: verdict.reason ?? "Forbidden" }, + { status: 403 } + ); + } + + return NextResponse.next(); +} + +export const config = { + matcher: "/api/:path*", +}; diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index 83f5e30..02e6fc3 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/entry-constants.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/lib/bundler.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","./node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/debug-channel.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/client/components/readonly-url-search-params.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/app-router-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/ppr-navigations.d.ts","./node_modules/next/dist/client/components/segment-cache/types.d.ts","./node_modules/next/dist/client/components/segment-cache/navigation.d.ts","./node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","./node_modules/next/dist/server/load-default-error-components.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/staged-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/shared/lib/size-limit.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/build/adapter/build-complete.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./.next/dev/types/routes.d.ts","./next-env.d.ts","./next.config.ts","./node_modules/esbuild/lib/main.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/rollup/dist/rollup.d.ts","./node_modules/tsup/node_modules/source-map/source-map.d.ts","./node_modules/tsup/dist/index.d.ts","./tsup.config.ts","./scripts/generate-test-data.ts","./src/core/types.ts","./src/core/paths.ts","./src/core/pricing.ts","./src/core/parser.ts","./node_modules/dayjs/locale/types.d.ts","./node_modules/dayjs/locale/index.d.ts","./node_modules/dayjs/index.d.ts","./src/core/discovery.ts","./src/core/fast-discovery.ts","./src/app/api/devlog/route.ts","./node_modules/@types/better-sqlite3/index.d.ts","./src/core/db-schema.ts","./src/core/db.ts","./src/app/api/health/route.ts","./src/core/types-project.ts","./src/core/project-adapter.ts","./src/lib/api-utils.ts","./node_modules/readdirp/esm/index.d.ts","./node_modules/chokidar/esm/handler.d.ts","./node_modules/chokidar/esm/index.d.ts","./src/core/stream-manager.ts","./src/core/file-watcher.ts","./src/core/types-dashboard.ts","./src/app/api/locks/route.ts","./src/app/api/projects/route.ts","./src/app/api/projects/active/route.ts","./src/core/process-manager.ts","./src/app/api/sessions/route.ts","./src/app/api/sessions/[id]/route.ts","./src/app/api/sessions/[id]/messages/route.ts","./src/app/api/sessions/[id]/stream/route.ts","./src/app/api/tasks/route.ts","./src/app/api/tasks/[id]/route.ts","./src/app/api/tasks/reorder/route.ts","./src/core/worktree-manager.ts","./src/app/api/worktrees/route.ts","./src/app/api/worktrees/[name]/route.ts","./node_modules/commander/typings/index.d.ts","./node_modules/commander/typings/esm.d.mts","./node_modules/chalk/source/vendor/ansi-styles/index.d.ts","./node_modules/chalk/source/vendor/supports-color/index.d.ts","./node_modules/chalk/source/index.d.ts","./node_modules/cli-spinners/index.d.ts","./node_modules/ora/index.d.ts","./node_modules/toml/index.d.ts","./src/core/config.ts","./node_modules/dayjs/plugin/relativetime.d.ts","./node_modules/dayjs/plugin/istoday.d.ts","./node_modules/dayjs/plugin/isyesterday.d.ts","./src/cli/utils/format.ts","./src/cli/utils/output.ts","./src/cli/commands/shared.ts","./src/core/cache.ts","./src/cli/commands/dashboard.ts","./src/cli/commands/init.ts","./src/cli/commands/sessions.ts","./src/cli/commands/show.ts","./src/cli/commands/today.ts","./src/cli/commands/search.ts","./src/cli/commands/stats.ts","./src/cli/commands/cost.ts","./src/cli/commands/statusline.ts","./src/cli/commands/setup-statusline.ts","./src/cli/commands/setup-tmux.ts","./src/cli/commands/serve.ts","./src/cli/cli.ts","./src/cli/index.ts","./src/cli/utils/paths.ts","./node_modules/clsx/clsx.d.mts","./node_modules/tailwind-merge/dist/types.d.ts","./src/core/dashboard-utils.ts","./src/hooks/use-devlog.ts","./src/hooks/use-locks.ts","./src/hooks/use-projects.ts","./src/hooks/use-session-chat.ts","./src/hooks/use-sessions.ts","./src/hooks/use-task-sessions.ts","./src/hooks/use-tasks.ts","./src/hooks/use-worktrees.ts","./node_modules/next/dist/compiled/@next/font/dist/types.d.ts","./node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","./node_modules/next/font/google/index.d.ts","./node_modules/@radix-ui/react-accessible-icon/dist/index.d.mts","./node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-collapsible/dist/index.d.mts","./node_modules/@radix-ui/react-accordion/dist/index.d.mts","./node_modules/@radix-ui/react-dismissable-layer/dist/index.d.mts","./node_modules/@radix-ui/react-focus-scope/dist/index.d.mts","./node_modules/@radix-ui/react-portal/dist/index.d.mts","./node_modules/@radix-ui/react-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-alert-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-aspect-ratio/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/dist/index.d.mts","./node_modules/@radix-ui/react-checkbox/dist/index.d.mts","./node_modules/@radix-ui/react-arrow/dist/index.d.mts","./node_modules/@radix-ui/rect/dist/index.d.mts","./node_modules/@radix-ui/react-popper/dist/index.d.mts","./node_modules/@radix-ui/react-roving-focus/dist/index.d.mts","./node_modules/@radix-ui/react-menu/dist/index.d.mts","./node_modules/@radix-ui/react-context-menu/dist/index.d.mts","./node_modules/@radix-ui/react-direction/dist/index.d.mts","./node_modules/@radix-ui/react-dropdown-menu/dist/index.d.mts","./node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-form/dist/index.d.mts","./node_modules/@radix-ui/react-hover-card/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-menubar/dist/index.d.mts","./node_modules/@radix-ui/react-visually-hidden/dist/index.d.mts","./node_modules/@radix-ui/react-navigation-menu/dist/index.d.mts","./node_modules/@radix-ui/react-one-time-password-field/dist/index.d.mts","./node_modules/@radix-ui/react-password-toggle-field/dist/index.d.mts","./node_modules/@radix-ui/react-popover/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-progress/dist/index.d.mts","./node_modules/@radix-ui/react-radio-group/dist/index.d.mts","./node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","./node_modules/@radix-ui/react-select/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-slider/dist/index.d.mts","./node_modules/@radix-ui/react-slot/dist/index.d.mts","./node_modules/@radix-ui/react-switch/dist/index.d.mts","./node_modules/@radix-ui/react-tabs/dist/index.d.mts","./node_modules/@radix-ui/react-toast/dist/index.d.mts","./node_modules/@radix-ui/react-toggle/dist/index.d.mts","./node_modules/@radix-ui/react-toggle-group/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/dist/index.d.mts","./node_modules/@radix-ui/react-tooltip/dist/index.d.mts","./node_modules/radix-ui/dist/index.d.mts","./src/components/ui/tooltip.tsx","./node_modules/lucide-react/dist/lucide-react.d.ts","./src/components/ui/select.tsx","./src/components/layout/sidebar.tsx","./src/components/layout/header.tsx","./node_modules/class-variance-authority/dist/types.d.ts","./node_modules/class-variance-authority/dist/index.d.ts","./src/components/ui/alert.tsx","./src/components/locks/conflict-alert.tsx","./src/app/layout.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/badge.tsx","./src/components/dashboard/command-stats-bar.tsx","./src/components/ui/scroll-area.tsx","./src/components/dashboard/active-sessions-panel.tsx","./node_modules/css-box-model/src/index.d.ts","./node_modules/@hello-pangea/dnd/dist/dnd.d.ts","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/textarea.tsx","./src/components/kanban/create-task-dialog.tsx","./src/components/kanban/task-detail-dialog.tsx","./src/components/dashboard/task-quick-view.tsx","./src/components/dashboard/parallel-worktrees-panel.tsx","./src/components/dashboard/conflict-alert-bar.tsx","./src/app/page.tsx","./src/components/devlog/stats-grid.tsx","./src/components/ui/skeleton.tsx","./src/app/devlog/page.tsx","./src/components/ui/table.tsx","./src/components/locks/lock-table.tsx","./src/app/locks/page.tsx","./src/components/sessions/process-indicator.tsx","./src/components/sessions/session-card.tsx","./src/components/sessions/launch-dialog.tsx","./src/app/sessions/page.tsx","./node_modules/@types/unist/index.d.ts","./node_modules/@types/hast/index.d.ts","./node_modules/vfile-message/lib/index.d.ts","./node_modules/vfile-message/index.d.ts","./node_modules/vfile/lib/index.d.ts","./node_modules/vfile/index.d.ts","./node_modules/unified/lib/callable-instance.d.ts","./node_modules/trough/lib/index.d.ts","./node_modules/trough/index.d.ts","./node_modules/unified/lib/index.d.ts","./node_modules/unified/index.d.ts","./node_modules/@types/mdast/index.d.ts","./node_modules/mdast-util-to-hast/lib/state.d.ts","./node_modules/mdast-util-to-hast/lib/footer.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/blockquote.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/delete.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/emphasis.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/footnote-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/heading.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/html.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/inline-code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list-item.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/paragraph.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/root.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/strong.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-cell.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-row.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/text.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/thematic-break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/index.d.ts","./node_modules/mdast-util-to-hast/lib/index.d.ts","./node_modules/mdast-util-to-hast/index.d.ts","./node_modules/remark-rehype/lib/index.d.ts","./node_modules/remark-rehype/index.d.ts","./node_modules/react-markdown/lib/index.d.ts","./node_modules/react-markdown/index.d.ts","./src/components/sessions/session-chat.tsx","./src/app/sessions/[id]/page.tsx","./src/components/kanban/task-card.tsx","./src/components/kanban/column.tsx","./src/components/kanban/board.tsx","./src/app/tasks/page.tsx","./src/components/worktrees/worktree-card.tsx","./src/components/ui/tabs.tsx","./src/components/worktrees/diff-viewer.tsx","./src/app/worktrees/page.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/progress.tsx","./src/components/ui/separator.tsx","./src/components/ui/switch.tsx","./.next/types/routes.d.ts","./.next/types/validator.ts","./.next/dev/types/cache-life.d.ts","./.next/dev/types/validator.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/debug/index.d.ts","./node_modules/@types/estree-jsx/index.d.ts","./node_modules/@types/statuses/index.d.ts","./node_modules/@types/use-sync-external-store/index.d.ts","./node_modules/@types/validate-npm-package-name/index.d.ts"],"fileIdsList":[[74,121,438,439,440,441],[74,121],[74,121,247,482,485,488,507,511,521,522,523,525,526,527,528,529,530,531,533,534,636,654,657,660,664,710,714,718],[74,121,247,482,485,507,511,521,522,523,525,526,527,528,529,530,531,533,534,636,654,657,660,664,710,714,718,723],[74,121,486,487,488],[74,121,247,486],[62,74,121,643],[62,74,121],[62,74,121,581,582,583],[62,74,121,581,588],[62,74,121,582],[62,74,121,581,582],[62,74,121,247,581,582],[62,74,121,581,582,597],[62,74,121,581,582,585,586,587],[62,74,121,247,581,582,601],[62,74,121,581,582,585,587,595],[62,74,121,581,582,585,586,587,595,596],[62,74,121,247,581,582,596,597],[62,74,121,581,582,585,606],[62,74,121,582,596],[62,74,121,581,582,585,586,587,595],[62,74,121,581,582,593,594],[62,74,121,581,582,596],[62,74,121,581,582,585],[62,74,121,581,582,596,621],[62,74,121,581,582,596,615,622],[74,121,169],[74,121,727],[74,121,492,493,729],[74,121,665],[74,118,121],[74,120,121],[121],[74,121,126,154],[74,121,122,127,132,140,151,162],[74,121,122,123,132,140],[69,70,71,74,121],[74,121,124,163],[74,121,125,126,133,141],[74,121,126,151,159],[74,121,127,129,132,140],[74,120,121,128],[74,121,129,130],[74,121,131,132],[74,120,121,132],[74,121,132,133,134,151,162],[74,121,132,133,134,147,151,154],[74,121,129,132,135,140,151,162],[74,121,132,133,135,136,140,151,159,162],[74,121,135,137,151,159,162],[72,73,74,75,76,77,78,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[74,121,132,138],[74,121,139,162,167],[74,121,129,132,140,151],[74,121,141],[74,121,142],[74,120,121,143],[74,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[74,121,145],[74,121,146],[74,121,132,147,148],[74,121,147,149,163,165],[74,121,132,151,152,154],[74,121,153,154],[74,121,151,152],[74,121,154],[74,121,155],[74,118,121,151,156],[74,121,132,157,158],[74,121,157,158],[74,121,126,140,151,159],[74,121,160],[74,121,140,161],[74,121,135,146,162],[74,121,126,163],[74,121,151,164],[74,121,139,165],[74,121,166],[74,116,121],[74,116,121,132,134,143,151,154,162,165,167],[74,121,151,168],[62,66,74,121,170,171,172,174,433,479],[62,66,74,121,170,171,172,173,390,433,479],[62,66,74,121,170,171,173,174,433,479],[62,74,121,174,390,391],[62,74,121,174,390],[62,66,74,121,171,172,173,174,433,479],[62,66,74,121,170,172,173,174,433,479],[60,61,74,121],[74,121,537,538],[74,121,161],[74,121,133,515,517],[74,121,132,133,515,516],[74,121,566,632],[74,121,566],[74,121,535],[74,121,503],[74,121,502],[74,121,504,544,546],[74,121,504,544,545],[74,121,504,545,546],[74,121,666,676,677,678,702,703,704],[74,121,666,677,704],[74,121,666,676,677,704],[74,121,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701],[74,121,666,670,676,678,704],[74,121,436],[74,121,179,181,185,196,386,416,429],[74,121,181,191,192,193,195,429],[74,121,181,228,230,232,233,236,429,431],[74,121,181,185,187,188,189,219,314,386,406,407,415,429,431],[74,121,429],[74,121,192,284,395,404,424],[74,121,181],[74,121,175,284,424],[74,121,238],[74,121,237,429],[74,121,135,384,395,484],[74,121,135,352,364,404,423],[74,121,135,295],[74,121,409],[74,121,408,409,410],[74,121,408],[68,74,121,135,175,181,185,188,190,192,196,197,210,211,238,314,325,405,416,429,433],[74,121,179,181,194,228,229,234,235,429,484],[74,121,194,484],[74,121,179,211,339,429,484],[74,121,484],[74,121,181,194,195,484],[74,121,231,484],[74,121,197,406,414],[74,121,146,247,424],[74,121,247,424],[62,74,121,247],[62,74,121,356],[74,121,282,292,293,424,461,468],[74,121,281,401,462,463,464,465,467],[74,121,400],[74,121,400,401],[74,121,219,284,285,289],[74,121,284],[74,121,284,288,290],[74,121,284,285,286,287],[74,121,466],[62,74,121,182,455],[62,74,121,162],[62,74,121,194,274],[62,74,121,194,416],[74,121,272,276],[62,74,121,273,435],[74,121,577],[62,66,74,121,135,169,170,171,172,173,174,433,477,478],[74,121,135],[74,121,135,185,218,270,315,336,338,411,412,416,429,430],[74,121,210,413],[74,121,433],[74,121,180],[62,74,121,341,354,363,373,375,423],[74,121,146,341,354,372,373,374,423,483],[74,121,366,367,368,369,370,371],[74,121,368],[74,121,372],[74,121,245,246,247,249],[62,74,121,239,240,241,242,248],[74,121,245,248],[74,121,243],[74,121,244],[62,74,121,247,273,435],[62,74,121,247,434,435],[62,74,121,247,435],[74,121,315,418],[74,121,418],[74,121,135,430,435],[74,121,360],[74,120,121,359],[74,121,220,284,301,338,347,350,352,353,394,423,426,430],[74,121,266,284,381],[74,121,352,423],[62,74,121,352,357,358,360,361,362,363,364,365,376,377,378,379,380,382,383,423,424,484],[74,121,346],[74,121,135,146,182,218,221,242,267,268,315,325,336,337,394,417,429,430,431,433,484],[74,121,423],[74,120,121,192,268,325,349,417,419,420,421,422,430],[74,121,352],[74,120,121,218,255,301,342,343,344,345,346,347,348,350,351,423,424],[74,121,135,255,256,342,430,431],[74,121,192,315,325,338,417,423,430],[74,121,135,429,431],[74,121,135,151,426,430,431],[74,121,135,146,162,175,185,194,220,221,223,252,257,262,266,267,268,270,299,301,303,306,308,311,312,313,314,336,338,416,417,424,426,429,430,431],[74,121,135,151],[74,121,181,182,183,190,426,427,428,433,435,484],[74,121,179,429],[74,121,251],[74,121,135,151,162,213,236,238,239,240,241,242,249,250,484],[74,121,146,162,175,213,228,261,262,263,299,300,301,306,314,315,321,324,326,336,338,417,424,426,429],[74,121,190,197,210,314,325,417,429],[74,121,135,162,182,185,301,319,426,429],[74,121,340],[74,121,135,251,322,323,333],[74,121,426,429],[74,121,347,349],[74,121,268,301,416,435],[74,121,135,146,224,228,300,306,321,324,328,426],[74,121,135,197,210,228,329],[74,121,181,223,331,416,429],[74,121,135,162,242,429],[74,121,135,194,222,223,224,233,251,330,332,416,429],[68,74,121,135,268,335,433,435],[74,121,298,336],[74,121,135,146,162,185,196,197,210,220,221,257,261,262,263,267,299,300,301,303,315,316,318,320,336,338,416,417,424,425,426,435],[74,121,135,151,197,321,327,333,426],[74,121,200,201,202,203,204,205,206,207,208,209],[74,121,252,307],[74,121,309],[74,121,307],[74,121,309,310],[74,121,135,185,188,218,219,430],[74,121,135,146,180,182,220,266,267,268,269,297,336,426,431,433,435],[74,121,135,146,162,184,219,269,301,347,417,425,430],[74,121,342],[74,121,343],[74,121,284,314,394],[74,121,344],[74,121,212,216],[74,121,135,185,212,220],[74,121,215,216],[74,121,217],[74,121,212,213],[74,121,212,264],[74,121,212],[74,121,252,305,425],[74,121,304],[74,121,213,424,425],[74,121,302,425],[74,121,213,424],[74,121,394],[74,121,185,214,220,268,284,301,335,338,341,347,354,355,385,386,389,393,416,426,430],[74,121,277,280,282,283,292,293],[62,74,121,172,174,247,387,388],[62,74,121,172,174,247,387,388,392],[74,121,403],[74,121,192,256,268,335,338,352,360,364,396,397,398,399,401,402,405,416,423,429],[74,121,292],[74,121,135,297],[74,121,297],[74,121,135,220,265,270,294,296,335,426,433,435],[74,121,277,278,279,280,282,283,292,293,434],[68,74,121,135,146,162,212,213,221,267,268,301,333,334,336,416,417,426,429,430,433],[74,121,256,258,261,417],[74,121,135,252,429],[74,121,255,352],[74,121,254],[74,121,256,257],[74,121,253,255,429],[74,121,135,184,256,258,259,260,429,430],[62,74,121,284,291,424],[74,121,177,178],[62,74,121,182],[62,74,121,281,424],[62,68,74,121,267,268,433,435],[74,121,182,455,456],[62,74,121,276],[62,74,121,146,162,180,235,271,273,275,435],[74,121,194,424,430],[74,121,317,424],[62,74,121,133,135,146,179,180,230,276,433,434],[62,74,121,170,171,172,173,174,433,479],[62,63,64,65,66,74,121],[74,121,126],[74,121,225,226,227],[74,121,225],[62,66,74,121,135,137,146,169,170,171,172,173,174,175,180,221,328,372,431,432,435,479],[74,121,443],[74,121,445],[74,121,447],[74,121,578],[74,121,449],[74,121,451,452,453],[74,121,457],[67,74,121,437,442,444,446,448,450,454,458,460,470,471,473,482,483,484,485],[74,121,459],[74,121,469],[74,121,273],[74,121,472],[74,120,121,256,258,259,261,474,475,476,479,480,481],[74,121,540],[74,121,580,583,584,587,588,589,590,591,592,598,599,600,601,602,603,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,624,625],[74,121,707],[62,74,121,666,675,704,706],[74,121,133,151],[74,121,704,705],[74,121,666,670,675,676,704],[74,121,151,169],[74,121,672],[74,121,491,493,494],[74,88,92,121,162],[74,88,121,151,162],[74,83,121],[74,85,88,121,159,162],[74,121,140,159],[74,83,121,169],[74,85,88,121,140,162],[74,80,81,84,87,121,132,151,162],[74,88,95,121],[74,80,86,121],[74,88,109,110,121],[74,84,88,121,154,162,169],[74,109,121,169],[74,82,83,121,169],[74,88,121],[74,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,121],[74,88,103,121],[74,88,95,96,121],[74,86,88,96,97,121],[74,87,121],[74,80,83,88,121],[74,88,92,96,97,121],[74,92,121],[74,86,88,91,121,162],[74,80,85,88,95,121],[74,121,151],[74,83,88,109,121,167,169],[74,121,670,674],[74,121,665,670,671,673,675],[74,121,667],[74,121,668,669],[74,121,665,668,670],[74,121,126,133,141,142,247],[74,121,247,482,499,505,506],[74,121,247,482,510],[74,121,247,482,510,514,519,520],[74,121,247,482,513],[74,121,247,482,510,520],[74,121,247,482,510,520,524],[74,121,247,482,510,518,520],[74,121,126,247,482,510,514,520,524],[74,121,247,482,510,514,520],[74,121,247,482,532],[74,121,247,482,514,532],[74,121,247,569,655,656],[74,121,247,486,579,627,630,631,635],[74,121,247,570,635,656,659],[62,74,121,247,460,570,573,575,576,628,637,638,640,642,651,652,653],[62,74,121,247,470,520,628,637,639,661,709],[74,121,247,573,628,656,662,663],[74,121,247,713],[62,74,121,247,576,628,637,645,646,647,656,715,717],[74,121,247,498,536,539,547,548,551,552,553,554,555,556,557,558,559,560,561,562],[74,121,247,498,504,505,539,541,543,545,547,548],[74,121,133,247,498,499,505,539,541,543,547,548,549,550],[74,121,133,247,498,499,505,539,541,543,547,548],[74,121,247,498,505,539,541,543,547,548,549],[74,121,122,133,142,247,498,539],[74,121,122,133,141,142,162,247,505,539,543,550],[74,121,122,133,141,142,162,247,539],[74,121,247,498],[74,121,247,498,501,505,539,541,543,547,548],[74,121,247,498,504,505,539,541,543,545,547,548,550],[74,121,133,141,142,247,498,504,506,543,550],[74,121,247,498,504,505,539,541,543,545,547,548,549],[74,121,247,498,499,500,501,505,506,543,547,548,550],[74,121,247,504,539,544,545,546],[74,121,247],[74,121,141,142,247],[74,121,247,460,504,520,544,628,639,641],[74,121,247,520,628,639],[62,74,121,247,628,637],[74,121,247,460,520,628,638,639],[62,74,121,247,520,568,575,628,637,639,641,644,649,650],[74,121,247,520,628,638],[62,74,121,247,520,574,575,644,649,650,656,712],[74,121,247,520,568,639,644,711],[62,74,121,247,520,628,629,637,645,646,647,648],[74,121,247,470,504,520,544,568,628,637,638,639,644],[62,74,121,247,470,520,568,628,629,637,639,645,646,647,648],[74,121,247,470],[74,121,247,460,470,568,571,628,629],[74,121,247,570,628,634],[74,121,247,520,628,637,639,658],[62,74,121,247,470,520,628,629,637,645,647,648],[74,121,247,520,568],[74,121,247,460,520,628,637,638,639,661],[62,74,121,247,568,572,628,637,648,708],[62,74,121,247,568,633],[62,74,121,247,568,626,633],[62,74,121,247,568],[62,74,121,247,568,626,628,637],[62,74,121,247,568,626,628],[62,74,121,247,568,626],[74,121,247,568],[62,74,121,247,638,641,656,716],[74,121,247,520,628,637,638,639],[74,121,133,142,247,498,499,504],[74,121,133,142,247,498,499,542],[74,121,247,566,567],[74,121,133,142,247,508,509],[74,121,133,134,142,247,498,499,501,504],[74,121,134,142,247,498,499,501,504],[74,121,142,247,510,517,518],[74,121,133,147,247,498,500],[74,121,122,133,147,247,510,518],[74,121,133,142,247,512],[74,121,122,142,163,247,513,520],[62,74,121,247,520],[62,74,121,247,520,573],[74,121,247,495]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"fad4e3c207fe23922d0b2d06b01acbfb9714c4f2685cf80fd384c8a100c82fd0","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"5c9b31919ea1cb350a7ae5e71c9ced8f11723e4fa258a8cc8d16ae46edd623c7","impliedFormat":1},{"version":"4aa42ce8383b45823b3a1d3811c0fdd5f939f90254bc4874124393febbaf89f6","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"3677988e03b749874eb9c1aa8dc88cd77b6005e5c4c39d821cda7b80d5388619","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"f4625edcb57b37b84506e8b276eb59ca30d31f88c6656d29d4e90e3bc58e69df","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"e2a37ac938c4bede5bb284b9d2d042da299528f1e61f6f57538f1bd37d760869","impliedFormat":1},{"version":"76def37aff8e3a051cf406e10340ffba0f28b6991c5d987474cc11137796e1eb","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"594fe24fc54645ab6ccb9dba15d3a35963a73a395b2ef0375ea34bf181ccfd63","impliedFormat":1},{"version":"7cb0ee103671d1e201cd53dda12bc1cd0a35f1c63d6102720c6eeb322cb8e17e","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"ad37fb4be61c1035b68f532b7220f4e8236cf245381ce3b90ac15449ecfe7305","impliedFormat":1},{"version":"93436bd74c66baba229bfefe1314d122c01f0d4c1d9e35081a0c4f0470ac1a6c","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"304b44b1e97dd4c94697c3313df89a578dca4930a104454c99863f1784a54357","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"97e5ccc7bb88419005cbdf812243a5b3186cdef81b608540acabe1be163fc3e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"6b3453eebd474cc8acf6d759f1668e6ce7425a565e2996a20b644c72916ecf75","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"89cd3444e389e42c56fd0d072afef31387e7f4107651afd2c03950f22dc36f77","impliedFormat":1},{"version":"7f2aa4d4989a82530aaac3f72b3dceca90e9c25bee0b1a327e8a08a1262435ad","impliedFormat":1},{"version":"e39a304f882598138a8022106cb8de332abbbb87f3fee71c5ca6b525c11c51fc","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"fcdf3e40e4a01b9a4b70931b8b51476b210c511924fcfe3f0dae19c4d52f1a54","impliedFormat":1},{"version":"345c4327b637d34a15aba4b7091eb068d6ab40a3dedaab9f00986253c9704e53","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"2b5b70d7782fe028487a80a1c214e67bd610532b9f978b78fa60f5b4a359f77e","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"7580e62139cb2b44a0270c8d01abcbfcba2819a02514a527342447fa69b34ef1","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"7e6ac205dcb9714f708354fd863bffa45cee90740706cc64b3b39b23ebb84744","impliedFormat":1},{"version":"61dc6e3ac78d64aa864eedd0a208b97b5887cc99c5ba65c03287bf57d83b1eb9","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"f730b468deecf26188ad62ee8950dc29aa2aea9543bb08ed714c3db019359fd9","impliedFormat":1},{"version":"933aee906d42ea2c53b6892192a8127745f2ec81a90695df4024308ba35a8ff4","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"144bc326e90b894d1ec78a2af3ffb2eb3733f4d96761db0ca0b6239a8285f972","impliedFormat":1},{"version":"a3e3f0efcae272ab8ee3298e4e819f7d9dd9ff411101f45444877e77cfeca9a4","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"71d9eb4c4e99456b78ae182fb20a5dfc20eb1667f091dbb9335b3c017dd1c783","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"30e6520444df1a004f46fdc8096f3fe06f7bbd93d09c53ada9dcdde59919ccca","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"a58beefce74db00dbb60eb5a4bb0c6726fb94c7797c721f629142c0ae9c94306","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"502fa5863df08b806dbf33c54bee8c19f7e2ad466785c0fc35465d7c5ff80995","impliedFormat":1},{"version":"c91a2d08601a1547ffef326201be26db94356f38693bb18db622ae5e9b3d7c92","impliedFormat":1},{"version":"888cda0fa66d7f74e985a3f7b1af1f64b8ff03eb3d5e80d051c3cbdeb7f32ab7","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"9586918b63f24124a5ca1d0cc2979821a8a57f514781f09fc5aa9cae6d7c0138","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"55095860901097726220b6923e35a812afdd49242a1246d7b0942ee7eb34c6e4","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"1a6e6ba8a07b74e3ad237717c0299d453f9ceb795dbc2f697d1f2dd07cb782d2","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"190da5eac6478d61ab9731ab2146fbc0164af2117a363013249b7e7992f1cccb","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"a46dba563f70f32f9e45ae015f3de979225f668075d7a427f874e0f6db584991","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"622694a8522b46f6310c2a9b5d2530dde1e2854cb5829354e6d1ff8f371cf469","impliedFormat":1},{"version":"d24ff95760ea2dfcc7c57d0e269356984e7046b7e0b745c80fea71559f15bdd8","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"13c1b657932e827a7ed510395d94fc8b743b9d053ab95b7cd829b2bc46fb06db","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"078131f3a722a8ad3fc0b724cd3497176513cdcb41c80f96a3acbda2a143b58e","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"9e155d2255348d950b1f65643fb26c0f14f5109daf8bd9ee24a866ad0a743648","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"7a883e9c84e720810f86ef4388f54938a65caa0f4d181a64e9255e847a7c9f51","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d408d6f32de8d1aba2ff4a20f1aa6a6edd7d92c997f63b90f8ad3f9017cf5e46","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"9d622ea608d43eb463c0c4538fd5baa794bc18ea0bb8e96cd2ab6fd483d55fe2","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"8add384e8ef68f0bff6722539a5672ac239a65e609b62dec95635b2c8d6ee846","affectsGlobalScope":true},"7ad303e40d4fddf44f156129e397511953a71481c5cfd86b1862649aaaf240cc","896029d28fe0ea1a074fbf66ad012258106857abe17bef77ae3a6799da44392a",{"version":"161c8e0690c46021506e32fda85956d785b70f309ae97011fd27374c065cac9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"ee70b8037ecdf0de6c04f35277f253663a536d7e38f1539d270e4e916d225a3f","affectsGlobalScope":true,"impliedFormat":1},{"version":"89dcbbf69b16cd94043e16c7fbcfa04256577ec98bb8ae894833d2a922394db4","impliedFormat":1},{"version":"e6ceaf94d57c812d95e43d034e093add2456041eace95ece0e24ccacd462b370","impliedFormat":1},"fbc85cbcecf5fa4ea4a191c0111e5b94abd1d1dd430da8ae234bf68791e6f924","0b3356552218a78b5807a37e35ebdf2d6e286ec688b5d36c90cf2cd11f950d9c","321227784adf046a4455b9d91350b4b4a74988553d8c2895865a7390b1502c23","89cd727fc52a37e95bf25bd7abdd10d3648b511c67fbf9242bf0564bf4a2a842","2a66023739bb1abb7ac44cdad034555291ce2f117048573a133f5163e48d176f","ef32980c4f0016361873d7a2d25787fd208741f901ce6b5207fff5aaced96b16",{"version":"73a0ee6395819b063df4b148211985f2e1442945c1a057204cf4cf6281760dc3","affectsGlobalScope":true,"impliedFormat":1},{"version":"d05d8c67116dceafc62e691c47ac89f8f10cf7313cd1b2fb4fe801c2bf1bb1a7","impliedFormat":1},{"version":"3c5bb5207df7095882400323d692957e90ec17323ccff5fd5f29a1ecf3b165d0","impliedFormat":1},"719703fbab3da4f46ee965b90bccaac9786238f260ee0e866d49b562d26b03f8","083b0dcd0a26ea9daa44618173c1c2dff0b5022f7801337b339a9a690cbe303b","88900077ef69fa1da02c49f76772a0f5004703dc730eb66c62361f2208244a68",{"version":"c2a6a737189ced24ffe0634e9239b087e4c26378d0490f95141b9b9b042b746c","impliedFormat":1},"6c9aed4e9f17b9be2e8d5780d5a2808347c0b0dcfa4c85fc58e598780501a887","e2d535b95388a929197c6dfe1c57391d15aeab82e5ade967458aa5373646ae86","22abee0b8236a1eab0d0296159bf712e4916e3a5d76735e393b285365ff7dfdd","de7adf4e7f759c4a67ff3263a6153da1f6430de5b74880f72d2d144d2b808b46","3cdcae5627195bf2e408a9b3ad6b5ad12cc3cfe97067093c78e225a0c9657efe","cc6fe493ff1e9ce823b13585bc4e1ad2c60b471046bddb84956f06e4d9a1585c",{"version":"d3a6e1ff56a0a760b1b36eb34925042a8148d8e0ab4c2d28fcbdbf40fb5a8acc","impliedFormat":99},{"version":"839114ddc4236b8304df6a6c7cc6784913b7c69a63afd4ecb36fc5c9c57276fc","impliedFormat":99},{"version":"cc4ecb6238b32248c6b58577a2ac2a6223c002c1a9e3f1f9424a89f44aa84f0a","impliedFormat":99},"fba9b67f5f2fe6ad2362aaaa7c572728a5e686591dca4760e5eca276d6b514c4","d8347f1c1b3cb0542d3b9c035a3fc60b29530a44bab488feb27a3b24cee8c065","4b77aef986758cf6135367366e29917e6bf54f3560a45812c0ef89db3b8a2217","2351254578af067c5c3de36ac1c095c32f5b7d33505443594ec31f6399977a5d","0626216ce593b877ca3ac04db6b233ae581f2197f41a71a493b99da15e51add0","e3f68a251d60cc53a6ab436bbb24bce62077a9f2250082f08f6b5f957dab114a","cf43f61c8a0288d280426618498dd81a4502699d861981d6c972b2cf9661b322","a446b1b2d731d90e97ced920a00312aa1bb7e6361b58f0e29e50a0006afbc679","086edfe5bd90955d69850702dfd5e8c1c75bfee4876c1183a58dfc897291ffb8","0754157c4a498a0e88d926dc22e93898d92c56759d953aad7c70bafb3365f47d","7ae234bab4e769f69aa9a29516b897c0f712078e215a736f17bdd862f7d7e8e8","5f29c24e1cf697ab82da4b4fd0956fb6848f6006efbffc159fcc91e17216bc91","5f5a5b2c6057bff493a55a308c5e175e7ff7ed67270fef6ba4c640706ccd07fd","92acc45d403b8931c35712650356998a4c559b61a7699e86fa426886fab46223","3696ef08c6ae8b727899f57bc08378db812b230f1f2a5590d341f47f1ba435c0","840bf8e79872842982837cec72b2fa05c52a4341d6b4c98a5af2e3ad2657c5fa","4f0c2a4fba22353838d27c00ddc1c74287c365efc874f8a9c2e178d877f12fff",{"version":"0237580177f1a858ab125992af8a6dfc29268fe7d4bac5308b9f462f88b0cd31","impliedFormat":1},{"version":"b124c0624b15412ace7d54644ade38d7a69db7e25488a1a4d2a8df6e11696538","impliedFormat":99},{"version":"acfed6cc001e7f7f26d2ba42222a180ba669bb966d4dd9cb4ad5596516061b13","impliedFormat":99},{"version":"f61a4dc92450609c353738f0a2daebf8cae71b24716dbd952456d80b1e1a48b6","impliedFormat":99},{"version":"f3f76db6e76bc76d13cc4bfa10e1f74390b8ebe279535f62243e8d8acd919314","impliedFormat":99},{"version":"6bbb2e249520ec6ddd60e970972603d415f0a0ef44c7329e4b8f56dc2442da09","impliedFormat":99},{"version":"8e1b740bd40321e66f88636d90e6db2254707adcde44e8daf5636780cc4a7318","impliedFormat":99},{"version":"a7fe7e88c50608567af53c49d3c59ea5f33bf5f59126d67b2a25f85eb41297ba","impliedFormat":1},"f10c64fd1a065596d04631f3eaface87359b3da5d06ece45137a53657d24e523",{"version":"f684f2969931de8fb9a5164f8c8f51aaea4025f4eede98406a17642a605c2842","impliedFormat":1},{"version":"1aaededa2ff9719b5f1babb9c91ca8b680f51308ffa941a8baf2bc7a8940847e","impliedFormat":1},{"version":"19836a9526f2b7907bf9853af6667e76b974a5fb4a1705e3da7398d81eb7c7c1","impliedFormat":1},"146467ad43eccd04ddf1bdc9f7d98b86d2a132ac8a1573c1dc617489b554c436","21f0a0bf1f09910cb34e530f1f61de01e96202ac67ad2660c180f8b43cb3f71a","7dbcdfa015725c7acbf74c03622685206f0330314660f5264d12dfab8a5c7b3d","ed9c530c419af5933502594eed3004323682d954b898b3869ef56dae2ffac812","e4a7c2fefd0332fe13c34b497fd66e17c90d44933a502cbca5b853e23d34d8f2","c5fdd9c8e3bc60c2fdae1a08bf9d36fa10672ba1b809cd5247f8c2c3b1d7c0c7","6e6cbd39f93e459928d38b8488a176a9d9171ad4e581046620e24649c07df8aa","42717344a2d06e652f34c1a84c72b90e459ed72a640ece06c795ba15461cd89c","879ee3ccbbf281e2594146867cedbed1ef2e08cba54c2f91415a42abd37c672c","9c20a12cd439f9def1933afa603e62b4e4e5852b943edc6999a221a56b7221ed","0a9ad266281a2127d544ef8827e8875d57a87c9b32e187adc39b97e2f56752f3","27122993af671d44cfd226f551df0ad4ce86b62e050123da385f93611044da03","bd10320d21f0e28849b8d264e6582777c904f0c91188c73e2818696172463094","783572e420a5af94543ba13053a00e10d06a034ddc947683990ceba5fcab672d","4be282ddc333a83c0558a1053ac699bb3d136f5b306b80d1deedc0b563f18f07","61d636743dc58831038abb0f19e28b6912bdf7bc52694ef974969984cca10021","35354011fdfcbcb0c9662b8703d7c599aeeedee33131ec2e1c7f56e93371e3f2","d651aff31ecc868e6262a675de501b30d74ce28ce26c3d3ace39e12240be4469","89cd727fc52a37e95bf25bd7abdd10d3648b511c67fbf9242bf0564bf4a2a842",{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"8658354b90861a76abc7b3c04ece2124295c7da0cc4c4d31c2c78d8607188d03","impliedFormat":1},"7c8c3dfc0cdd370d44932828eb067ef771c8fe7996693221d5d4b90af6d54f2d","ba68e3cd48f169879f5c064a7c04f15728e9b7aa7a2304fbeaebe0ed42611ac5","22efa664b6e4d134773c8c56bc44f036e5bb0d186d88478afd04a5a0dbd4b077","fbeef0e5fd7481f4dad55798fe436cd4ad80ca783831c10083c785afc40504e5","ac13914a381b7cbf60348491e793c21f9b0848acd87f171231608d1ec6878e3a","62294f460ba15324bbc053d3d448bc56f22a9797e2c03a56102f499158d0d5e7","237f042221038006e36415ff5df61c44ec5e55dcc28d6093cae4aaf6737044e0","8fd9cd6f750651120418f45557cbb31f51420a6dea5489fc3d0172d81b498506","8265f5c7c3a7273403c53367d751c646aa1c95c57f198f324f9033c726201dd5",{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"f5705d196b442afbdbd971b6e44bad96f4e32afb53cebfa2e5afe3140017bfc6","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},{"version":"024829c0b317972acf4f871bf701525f81896ad74015f1a52d46ae6036205cb9","impliedFormat":99},{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"0943a6e4e026d0de8a4969ee975a7283e0627bf41aa4635d8502f6f24365ac9b","impliedFormat":99},{"version":"1461efc4aefd3e999244f238f59c9b9753a7e3dfede923ebe2b4a11d6e13a0d0","impliedFormat":99},{"version":"7ec047b73f621c526468517fea779fec2007dd05baa880989def59126c98ef79","impliedFormat":99},{"version":"8dd450de6d756cee0761f277c6dc58b0b5a66b8c274b980949318b8cad26d712","impliedFormat":99},{"version":"904d6ad970b6bd825449480488a73d9b98432357ab38cf8d31ffd651ae376ff5","impliedFormat":99},{"version":"dfcf16e716338e9fe8cf790ac7756f61c85b83b699861df970661e97bf482692","impliedFormat":99},{"version":"31c30cc54e8c3da37c8e2e40e5658471f65915df22d348990d1601901e8c9ff3","impliedFormat":99},{"version":"36d8011f1437aecf0e6e88677d933e4fb3403557f086f4ac00c5a4cb6d028ac2","impliedFormat":99},{"version":"8085954ba165e611c6230596078063627f3656fed3fb68ad1e36a414c4d7599a","impliedFormat":99},{"version":"2c57db2bf2dbd9e8ef4853be7257d62a1cb72845f7b976bb4ee827d362675f96","impliedFormat":99},{"version":"6b5f886fe41e2e767168e491fe6048398ed6439d44e006d9f51cc31265f08978","impliedFormat":99},{"version":"56a87e37f91f5625eb7d5f8394904f3f1e2a90fb08f347161dc94f1ae586bdd0","impliedFormat":99},{"version":"6b863463764ae572b9ada405bf77aac37b5e5089a3ab420d0862e4471051393b","impliedFormat":99},{"version":"68b6a7501a56babd7bcd840e0d638ee7ec582f1e70b3c36ebf32e5e5836913c8","impliedFormat":99},{"version":"89783bd45ab35df55203b522f8271500189c3526976af533a599a86caaf31362","impliedFormat":99},{"version":"6da2e0928bdab05861abc4e4abebea0c7cf0b67e25374ba35a94df2269563dd8","impliedFormat":99},{"version":"e7b00bec016013bcde74268d837a8b57173951add2b23c8fd12ffe57f204d88f","impliedFormat":99},{"version":"26e6c521a290630ea31f0205a46a87cab35faac96e2b30606f37bae7bcda4f9d","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"044047026c70439867589d8596ffe417b56158a1f054034f590166dd793b676b","impliedFormat":99},{"version":"89ad9a4e8044299f356f38879a1c2176bc60c997519b442c92cc5a70b731a360","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"fd4f58cd6b5fc8ce8af0d04bfef5142f15c4bafaac9a9899c6daa056f10bb517","impliedFormat":99},{"version":"2a00cea77767cb26393ee6f972fd32941249a0d65b246bfcb20a780a2b919a21","impliedFormat":99},{"version":"440cb5b34e06fabe3dcb13a3f77b98d771bf696857c8e97ce170b4f345f8a26b","impliedFormat":99},{"version":"5bc7f0946c94e23765bd1b8f62dc3ab65d7716285ca7cf45609f57777ddb436f","impliedFormat":99},{"version":"7d5a5e603a68faea3d978630a84cacad7668f11e14164c4dd10224fa1e210f56","impliedFormat":99},{"version":"2535fc1a5fe64892783ff8f61321b181c24f824e688a4a05ae738da33466605b","impliedFormat":99},{"version":"cbfd5ef0c8fdb4983202252b5f5758a579f4500edc3b9ad413da60cffb5c3564","impliedFormat":99},{"version":"9f7a3c434912fd3feb87af4aabdf0d1b614152ecb5e7b2aa1fff3429879cdd51","impliedFormat":99},{"version":"99d1a601593495371e798da1850b52877bf63d0678f15722d5f048e404f002e4","impliedFormat":99},{"version":"1179ef8174e0e4a09d35576199df04803b1db17c0fb35b9326442884bc0b0cce","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"cc3738ba01d9af5ba1206a313896837ff8779791afcd9869e582783550f17f38","impliedFormat":99},{"version":"a80ec72f5e178862476deaeed532c305bdfcd3627014ae7ac2901356d794fc93","impliedFormat":99},{"version":"4a5aa16151dbec524bb043a5cbce2c3fec75957d175475c115a953aca53999a9","impliedFormat":99},{"version":"7a14bf21ae8a29d64c42173c08f026928daf418bed1b97b37ac4bb2aa197b89b","impliedFormat":99},{"version":"c5013d60cbff572255ccc87c314c39e198c8cc6c5aa7855db7a21b79e06a510f","impliedFormat":99},{"version":"69ec8d900cfec3d40e50490fedbbea5c1b49d32c38adbc236e73a3b8978c0b11","impliedFormat":99},{"version":"7fd629484ba6772b686885b443914655089246f75a13dd685845d0abae337671","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"13dcccb62e8537329ac0448f088ab16fe5b0bbed71e56906d28d202072759804","impliedFormat":99},{"version":"233267a4a036c64aee95f66a0d31e3e0ef048cccc57dd66f9cf87582b38691e4","impliedFormat":99},{"version":"ccb9fbe369885d02cf6c2b2948fb5060451565d37b04356bbe753807f98e0682","impliedFormat":99},"77eb0c60ac30b7da409d462da64449ef819339aaf38e15587b84dd5b8f22040f",{"version":"d7dfba64b7350cb9501c544fe8ceba1b2455b42029d22b1a4fd02e94a6783525","impliedFormat":1},"300e46eb63f0b333a98ecdf90de67e6adf6aa0bd791dd8710ac03cf78293c27f","b20fdc201ad4d14c79683b13ebc46479ea6d7e78895a47f11cf087ec555c0652","ce569927b857abd3c146543a269d992e0657450c378073ab7edad358db7e56c6",{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},"0d14b3470b09270093b19111de70964fb88c06641c1dc3020a89ea64064e9418","b3753b9221a306f9dd489952deee232c9274490a02670c72f4367eb786f960bd","87c8e4d9f86502d6f68af00ffdc2bef8b9cf85d95e947fca73601d248e3bf677","91d6b4d149d8b8e92e1b6f6a716aa9de4d4b0516b818fef43923100e045bb52c","afe7006d37b92707b28ec7e0db00b3d267e7d776c36998867afd5171772e7e4b","7642d023b24a165bd92b4ecbf2b96665a224f7d7f1fa93b9ae308ac9d50dc101","080596978b4428bd4d5a945e81ead23cb27bfe55892ab757e4885d82f5561e20","d6b1569f5aeaa6e763bba5a188958100bd22a06677a1b55b4962107c7e324a0e","623ee4f87660cf41ef7befe5df8ef7698f8518bd5479bf474cb6f60d0d2b94c9",{"version":"cc0db34c3fa72ad32b36db06b2921b228ddc3921cf91076ce762c550ff28a265","impliedFormat":1},{"version":"39cec3d65003f318688e3a4d0afe09727ca2d588d4c157a6dcbfeee57a63f5b0","impliedFormat":1},"74ff76c709f5e3ceb17076240228814eba7a0ff132806c3517536be0839e2dc3","5ba09493d0df0e34a69f0b7a9c78ca5ddef2fadc1084825f0422f42acb021e5b","05790534533bfb89097e921ab621c106b670aa942def56efcacca9b9f326ccff","28c5d9aa4362d575e7446e52a7e175c545c0aa0a7389d1a7f2cafad726a3b860","ca83a1279bd3ffb830a94cec8ae174cd78b8ffc5f58ba5128e80f4158623f53a","0fcdf87a07ca9d0ed281ce95d964165acc93261c6d3cca1c49236daf5f38a1a5","0ecdeed7be0a15b69f0ebbb69cb525ca0894a248ef5c480bba6162788c1e7026","bbeb2f7ac5cde5ae87370ec5e9ba75a560f7cc4d64ba9de61938f234173e7074","772112ae145bd37e3f237d71fe607d68e7d30504de62c258f3ab031b91acf1d2","23cd9f5076375f2988c17172bc9dce1c6622045f1831757dca1ee420db627aaf","b62b159e14eb3ad46e830c94509eccbe1e3757b473905cbfce3905665c50cf9c","4ddd72fa5c7491ca175087b8c7cfba2710f560961c4ab790519b9203c6cdf01c","6f8145b1966297bf8ee39023a3e1b4985021de01d467f120783375382ff40e69","b2f52dc18fc56d792e62194014006dfef3f21e8ccee687e620e010222609411a","037ab3e7f898bb6a441320748b7a2468682370aa6c5abeae6d6f457a57958334","2908e14681d109d8ecb2a82da30809b4e3d0fac40a1a1c94bfb90f766f47abad","6e1d99a97b32702d6980a847df4fe4121b1e1e441881ad35cdc09dabbb8c286e","529bd133a2d8edfd984d934fed032f2b3c647a2ba94c7b7671a80df7027fdc7f","f1f756d9cfa17df9a0a766714772a3f2bc919f39d6ac7434a43f90525aa016ba","d9175acc420fa3be1252dae91687f30703b08e6dde2a96d114e99b802ca5b33f",{"version":"89121c1bf2990f5219bfd802a3e7fc557de447c62058d6af68d6b6348d64499a","impliedFormat":1},{"version":"79b4369233a12c6fa4a07301ecb7085802c98f3a77cf9ab97eee27e1656f82e6","impliedFormat":1},{"version":"2b37ba54ec067598bf912d56fcb81f6d8ad86a045c757e79440bdef97b52fe1b","impliedFormat":99},{"version":"1bc9dd465634109668661f998485a32da369755d9f32b5a55ed64a525566c94b","impliedFormat":99},{"version":"5702b3c2f5d248290ed99419d77ca1cc3e6c29db5847172377659c50e6303768","impliedFormat":99},{"version":"9764b2eb5b4fc0b8951468fb3dbd6cd922d7752343ef5fbf1a7cd3dfcd54a75e","impliedFormat":99},{"version":"1fc2d3fe8f31c52c802c4dee6c0157c5a1d1f6be44ece83c49174e316cf931ad","impliedFormat":99},{"version":"dc4aae103a0c812121d9db1f7a5ea98231801ed405bf577d1c9c46a893177e36","impliedFormat":99},{"version":"106d3f40907ba68d2ad8ce143a68358bad476e1cc4a5c710c11c7dbaac878308","impliedFormat":99},{"version":"42ad582d92b058b88570d5be95393cf0a6c09a29ba9aa44609465b41d39d2534","impliedFormat":99},{"version":"36e051a1e0d2f2a808dbb164d846be09b5d98e8b782b37922a3b75f57ee66698","impliedFormat":99},{"version":"d4a22007b481fe2a2e6bfd3a42c00cd62d41edb36d30fc4697df2692e9891fc8","impliedFormat":1},{"version":"9d62e577adb05f5aafed137e747b3a1b26f8dce7b20f350d22f6fb3255a3c0ed","impliedFormat":99},{"version":"7ed92bcef308af6e3925b3b61c83ad6157a03ff15c7412cf325f24042fe5d363","impliedFormat":99},{"version":"3da9062d0c762c002b7ab88187d72e1978c0224db61832221edc8f4eb0b54414","impliedFormat":99},{"version":"84dbf6af43b0b5ad42c01e332fddf4c690038248140d7c4ccb74a424e9226d4d","impliedFormat":99},{"version":"00884fc0ea3731a9ffecffcde8b32e181b20e1039977a8ae93ae5bce3ab3d245","impliedFormat":99},{"version":"0bd8b6493d9bf244afe133ccb52d32d293de8d08d15437cca2089beed5f5a6b5","impliedFormat":99},{"version":"7fc3099c95752c6e7b0ea215915464c7203e835fcd6878210f2ce4f0dcbbfe67","impliedFormat":99},{"version":"83b5499dbc74ee1add93aef162f7d44b769dcef3a74afb5f80c70f9a5ce77cc0","impliedFormat":99},{"version":"8bf8b772b38fc4da471248320f49a2219c363a9669938c720e0e0a5a2531eabf","impliedFormat":99},{"version":"7da6e8c98eacf084c961e039255f7ebb9d97a43377e7eee2695cb77fec640c66","impliedFormat":99},{"version":"0b5b064c5145a48cd3e2a5d9528c63f49bac55aa4bc5f5b4e68a160066401375","impliedFormat":99},{"version":"702ff40d28906c05d9d60b23e646c2577ad1cc7cd177d5c0791255a2eab13c07","impliedFormat":99},{"version":"49ff0f30d6e757d865ae0b422103f42737234e624815eee2b7f523240aa0c8f8","impliedFormat":99},{"version":"0389aacf0ffd49a877a46814a21a4770f33fc33e99951a1584de866c8e971993","impliedFormat":99},{"version":"5cb7a51cf151c1056b61f078cf80b811e19787d1f29a33a2a6e4bf00334bbc10","impliedFormat":99},{"version":"215aa8915d707f97ad511b7abbf7eda51d3a7048e9a656955cf0dda767ae7db0","impliedFormat":99},{"version":"0d689a717fbef83da07ab4de33f83db5cbcec9bc4e3b04edb106c538a50a0210","impliedFormat":99},{"version":"d00bc73e8d1f4137f2f6238bb3aa2bbdad8573658cc95920e2cdfa7ad491a8d8","impliedFormat":99},{"version":"e3667aa9f5245d1a99fb4a2a1ac48daf1429040c29cc0d262e3843f9ae3b9d65","impliedFormat":99},{"version":"08c0f3222b50ec2b534be1a59392660102549129246425d33ec43f35aa051dc6","impliedFormat":99},{"version":"612fb780f312e6bb3c40f3cb2b827ea7455b922198f651c799d844fdd44cf2e9","impliedFormat":99},{"version":"bcd98e8f44bc76e4fcb41e4b1a8bab648161a942653a3d1f261775a891d258de","impliedFormat":99},{"version":"5abaa19aa91bb4f63ea58154ada5d021e33b1f39aa026ca56eb95f13b12c497a","impliedFormat":99},{"version":"356a18b0c50f297fee148f4a2c64b0affd352cbd6f21c7b6bfa569d30622c693","impliedFormat":99},{"version":"5876027679fd5257b92eb55d62efee634358012b9f25c5711ad02b918e52c837","impliedFormat":99},{"version":"f5622423ee5642dcf2b92d71b37967b458e8df3cf90b468675ff9fddaa532a0f","impliedFormat":99},{"version":"70265bc75baf24ec0d61f12517b91ea711732b9c349fceef71a446c4ff4a247a","impliedFormat":99},{"version":"41a4b2454b2d3a13b4fc4ec57d6a0a639127369f87da8f28037943019705d619","impliedFormat":99},{"version":"e9b82ac7186490d18dffaafda695f5d975dfee549096c0bf883387a8b6c3ab5a","impliedFormat":99},{"version":"eed9b5f5a6998abe0b408db4b8847a46eb401c9924ddc5b24b1cede3ebf4ee8c","impliedFormat":99},{"version":"af85fde8986fdad68e96e871ae2d5278adaf2922d9879043b9313b18fae920b1","impliedFormat":99},{"version":"8a1f5d2f7cf4bf851cc9baae82056c3316d3c6d29561df28aff525556095554b","impliedFormat":99},"9da6b7947d6142f8cba95be795cf9ff46404330dbe54d42b699ee4f59572c5ad","45a41f288a4c5c4644652185763d73fa44b1ee94bed9d1b0d4aef06d1f7ccedb","40f3f895cd91487031d784be57a9b01be58d851b3db1cf0e51a4cb8e4095a5c3","498ba77990843053ad87788e13adfd8c45f404d3e5d351157b9cd48235266793","5253933c5f8e07db0008275f30a1f0c40a5ab06930dbf26bbfd08b35f80dfe4e","3fb176d1fca38c42cf87c5685e177789457ca463a0fcad5ecee0917f4a6eef67","2d6771f971781cf86ebe59c6f206c0a7fa237d361d32c62c6778f53034e4b4e1","2fed8019f865cb0200606eea95cc89c41db2bfb85183a44dff626ac5a0502000","42fdc31f8ac3965c84b5d7acbf86e982c43f7c3c6c07e08e5484335ca1c9c5d1","7cb9cfc82c15eec3a953194c87e3f585bc429b5d2173553587fc46244fd7dec5","673cfdfcfc12d7568bead946f93e06718eb9a518ca25b041af0145b0b590891b","f9ba280ed9e3f159e8813fcda71b5255dd1c54735890a1aba7e1a383413bdc26","f4e61e53002aa59dd7a516f83e6230228b486d69733345001efbcc6a0ddb9d67","5c3899347135fd5940962d9f68926eb38255898f138c7ca6e78e08fed99ef71a",{"version":"8add384e8ef68f0bff6722539a5672ac239a65e609b62dec95635b2c8d6ee846","affectsGlobalScope":true},"940efb0099e2379ef2f070f2d46d79597a9c86a4266742164b2689b093ddca3e","d1986184a09a52db8228cb2bb2a61a8c05c9354e5b93cec8e2628d8579c892d7","cf716fa0d83f23ba69eb191ca5257d98680951bf49cc006e93e0a40de3260bd2",{"version":"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","impliedFormat":1},{"version":"3eb11dbf3489064a47a2e1cf9d261b1f100ef0b3b50ffca6c44dd99d6dd81ac1","impliedFormat":1},{"version":"5d08a179b846f5ee674624b349ebebe2121c455e3a265dc93da4e8d9e89722b4","impliedFormat":1},{"version":"1f4ae755492a669b317903a6b1664cb7af3fe0c3d1eec6447f4e95a80616d15a","impliedFormat":1},{"version":"7fa8d75d229eeaee235a801758d9c694e94405013fe77d5d1dd8e3201fc414f1","impliedFormat":1},{"version":"0b301e46295e7dee8bcead624b4a0f94ab8ba1cb3f572b726977322293be2196","impliedFormat":1}],"root":[[488,490],[496,501],[505,507],[509,514],[518,534],543,[547,565],[568,576],627,[629,631],[634,642],[645,664],[709,726]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":9},"referencedMap":[[725,1],[488,2],[726,3],[723,2],[724,4],[489,5],[490,6],[644,7],[230,2],[580,8],[584,9],[589,10],[593,11],[590,11],[591,12],[592,13],[583,12],[598,14],[581,8],[588,15],[599,8],[585,11],[600,14],[586,11],[602,16],[601,11],[603,17],[597,18],[605,19],[607,20],[608,21],[609,8],[610,22],[595,23],[587,11],[582,8],[612,24],[596,12],[613,12],[614,22],[616,12],[617,8],[618,12],[619,24],[620,25],[622,26],[621,11],[624,27],[623,11],[625,17],[606,11],[594,2],[508,28],[728,29],[729,30],[492,2],[666,31],[676,31],[727,2],[118,32],[119,32],[120,33],[74,34],[121,35],[122,36],[123,37],[69,2],[72,38],[70,2],[71,2],[124,39],[125,40],[126,41],[127,42],[128,43],[129,44],[130,44],[131,45],[132,46],[133,47],[134,48],[75,2],[73,2],[135,49],[136,50],[137,51],[169,52],[138,53],[139,54],[140,55],[141,56],[142,57],[143,58],[144,59],[145,60],[146,61],[147,62],[148,62],[149,63],[150,2],[151,64],[153,65],[152,66],[154,67],[155,68],[156,69],[157,70],[158,71],[159,72],[160,73],[161,74],[162,75],[163,76],[164,77],[165,78],[166,79],[76,2],[77,2],[78,2],[117,80],[167,81],[168,82],[173,83],[390,8],[174,84],[172,85],[392,86],[391,87],[170,88],[388,2],[171,89],[60,2],[62,90],[387,8],[247,8],[730,2],[665,2],[731,2],[732,2],[79,2],[539,91],[537,2],[538,92],[516,93],[517,94],[633,95],[632,96],[540,2],[566,2],[536,97],[535,2],[643,2],[61,2],[504,98],[503,99],[502,2],[545,100],[546,101],[544,102],[491,2],[628,8],[704,103],[678,104],[679,105],[680,105],[681,105],[682,105],[683,105],[684,105],[685,105],[686,105],[687,105],[688,105],[702,106],[689,105],[690,105],[691,105],[692,105],[693,105],[694,105],[695,105],[696,105],[698,105],[699,105],[697,105],[700,105],[701,105],[703,105],[677,107],[437,108],[442,1],[432,109],[194,110],[234,111],[416,112],[229,113],[211,2],[386,2],[192,2],[405,114],[260,115],[193,2],[314,116],[237,117],[238,118],[385,119],[402,120],[296,121],[410,122],[411,123],[409,124],[408,2],[406,125],[236,126],[195,127],[339,2],[340,128],[266,129],[196,130],[267,129],[262,129],[183,129],[232,131],[231,2],[415,132],[427,2],[219,2],[361,133],[362,134],[356,8],[464,2],[364,2],[365,135],[357,136],[469,137],[468,138],[463,2],[281,2],[401,139],[400,2],[462,140],[358,8],[290,141],[286,142],[291,143],[289,2],[288,144],[287,2],[465,2],[461,2],[467,145],[466,2],[285,142],[456,146],[459,147],[275,148],[274,149],[273,150],[472,8],[272,151],[254,2],[475,2],[578,152],[577,2],[478,2],[477,8],[479,153],[176,2],[412,154],[413,155],[414,156],[189,2],[222,2],[188,157],[175,2],[377,8],[181,158],[376,159],[375,160],[366,2],[367,2],[374,2],[369,2],[372,161],[368,2],[370,162],[373,163],[371,162],[191,2],[186,2],[187,129],[242,2],[248,164],[249,165],[246,166],[244,167],[245,168],[240,2],[383,135],[269,135],[436,169],[443,170],[447,171],[419,172],[418,2],[257,2],[480,173],[431,174],[359,175],[360,176],[354,177],[345,2],[382,178],[421,8],[346,179],[384,180],[379,181],[378,2],[380,2],[351,2],[338,182],[420,183],[423,184],[348,185],[352,186],[343,187],[397,188],[430,189],[300,190],[315,191],[184,192],[429,193],[180,194],[250,195],[241,2],[251,196],[327,197],[239,2],[326,198],[68,2],[320,199],[221,2],[341,200],[316,2],[185,2],[215,2],[324,201],[190,2],[252,202],[350,203],[417,204],[349,2],[323,2],[243,2],[329,205],[330,206],[407,2],[332,207],[334,208],[333,209],[224,2],[322,192],[336,210],[299,211],[321,212],[328,213],[199,2],[203,2],[202,2],[201,2],[206,2],[200,2],[209,2],[208,2],[205,2],[204,2],[207,2],[210,214],[198,2],[308,215],[307,2],[312,216],[309,217],[311,218],[313,216],[310,217],[220,219],[270,220],[426,221],[481,2],[451,222],[453,223],[347,224],[452,225],[424,183],[363,183],[197,2],[301,226],[216,227],[217,228],[218,229],[214,230],[396,230],[264,230],[302,231],[265,231],[213,232],[212,2],[306,233],[305,234],[304,235],[303,236],[425,237],[395,238],[394,239],[355,240],[389,241],[393,242],[404,243],[403,244],[399,245],[298,246],[295,247],[297,248],[294,249],[335,250],[325,2],[441,2],[337,251],[398,2],[253,252],[344,154],[342,253],[255,254],[258,255],[476,2],[256,256],[259,256],[439,2],[438,2],[440,2],[474,2],[261,257],[422,2],[292,258],[284,8],[235,2],[179,259],[268,2],[445,8],[178,2],[455,260],[283,8],[449,135],[282,261],[434,262],[280,260],[182,2],[457,263],[278,8],[279,8],[271,2],[177,2],[277,264],[276,265],[223,266],[353,61],[263,61],[331,2],[318,267],[317,2],[381,142],[293,8],[428,157],[435,268],[63,8],[66,269],[67,270],[64,8],[65,2],[233,271],[228,272],[227,2],[226,273],[225,2],[433,274],[444,275],[446,276],[448,277],[579,278],[450,279],[454,280],[487,281],[458,281],[486,282],[460,283],[470,284],[471,285],[473,286],[482,287],[485,157],[484,2],[483,28],[541,288],[626,289],[604,11],[611,12],[615,11],[708,290],[707,291],[515,292],[706,293],[705,294],[493,30],[319,295],[567,2],[542,2],[673,296],[672,2],[495,297],[494,2],[58,2],[59,2],[10,2],[11,2],[13,2],[12,2],[2,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[20,2],[21,2],[3,2],[22,2],[23,2],[4,2],[24,2],[28,2],[25,2],[26,2],[27,2],[29,2],[30,2],[31,2],[5,2],[32,2],[33,2],[34,2],[35,2],[6,2],[39,2],[36,2],[37,2],[38,2],[40,2],[7,2],[41,2],[46,2],[47,2],[42,2],[43,2],[44,2],[45,2],[8,2],[51,2],[48,2],[49,2],[50,2],[52,2],[9,2],[53,2],[54,2],[55,2],[57,2],[56,2],[1,2],[95,298],[105,299],[94,298],[115,300],[86,301],[85,302],[114,28],[108,303],[113,304],[88,305],[102,306],[87,307],[111,308],[83,309],[82,28],[112,310],[84,311],[89,312],[90,2],[93,312],[80,2],[116,313],[106,314],[97,315],[98,316],[100,317],[96,318],[99,319],[109,28],[91,320],[92,321],[101,322],[81,323],[104,314],[103,312],[107,2],[110,324],[675,325],[671,2],[674,326],[668,327],[667,31],[670,328],[669,329],[497,330],[507,331],[511,332],[521,333],[523,334],[522,334],[527,335],[526,336],[528,337],[525,338],[530,335],[531,332],[529,339],[534,340],[533,341],[657,342],[636,343],[660,344],[654,345],[710,346],[664,347],[714,348],[718,349],[563,350],[558,351],[551,352],[552,353],[556,354],[562,355],[553,354],[560,356],[561,357],[549,358],[554,359],[557,360],[559,361],[555,362],[564,363],[547,364],[548,365],[565,366],[642,367],[640,368],[653,369],[652,370],[651,371],[655,372],[713,373],[712,374],[649,375],[711,376],[650,377],[631,378],[630,379],[635,380],[659,381],[663,382],[661,383],[662,384],[709,385],[634,386],[639,387],[637,387],[638,388],[645,389],[719,390],[646,388],[647,391],[720,391],[641,391],[629,390],[721,391],[656,392],[722,391],[658,388],[716,387],[648,388],[627,391],[717,393],[715,394],[550,395],[543,396],[568,397],[509,365],[510,398],[505,399],[506,400],[519,401],[501,402],[499,366],[500,358],[524,403],[513,404],[518,365],[520,365],[512,365],[498,365],[532,405],[569,406],[570,406],[571,135],[572,135],[573,406],[574,407],[575,406],[576,406],[514,334],[496,408]],"affectedFilesPendingEmit":[726,724,490,497,507,511,521,523,522,527,526,528,525,530,531,529,534,533,657,636,660,654,710,664,714,718,563,558,551,552,556,562,553,560,561,549,554,557,559,555,564,547,548,565,642,640,653,652,651,655,713,712,649,711,650,631,630,635,659,663,661,662,709,634,639,637,638,645,719,646,647,720,641,629,721,656,722,658,716,648,627,717,715,550,543,568,509,510,505,506,519,501,499,500,524,513,518,520,512,498,532,569,570,571,572,573,574,575,576,514,496],"version":"5.9.3"} \ No newline at end of file +{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/entry-constants.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/lib/bundler.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","./node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/debug-channel.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/client/components/readonly-url-search-params.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/app-router-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/ppr-navigations.d.ts","./node_modules/next/dist/client/components/segment-cache/types.d.ts","./node_modules/next/dist/client/components/segment-cache/navigation.d.ts","./node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","./node_modules/next/dist/server/load-default-error-components.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/staged-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/shared/lib/size-limit.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/build/adapter/build-complete.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./next-env.d.ts","./next.config.ts","./node_modules/esbuild/lib/main.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/rollup/dist/rollup.d.ts","./node_modules/source-map/source-map.d.ts","./node_modules/tsup/dist/index.d.ts","./tsup.config.ts","./scripts/generate-test-data.ts","./src/core/local-cli-agent-definitions.ts","./src/core/agent-settings.ts","./src/core/session-runtime-auth.ts","./src/core/api-provider-runtime.ts","./node_modules/@types/better-sqlite3/index.d.ts","./src/core/agent-presets.ts","./src/core/db-schema.ts","./src/core/db.ts","./src/core/types-dashboard.ts","./src/core/stream-manager.ts","./src/core/control-plane-protocol.ts","./src/core/types-project.ts","./src/core/project-adapter.ts","./src/core/worktree-manager.ts","./src/core/task-status-flow.ts","./src/core/task-lifecycle.ts","./src/core/api-session-runtime.ts","./src/core/local-cli-agents.ts","./src/core/process-manager.ts","./src/core/agent-connection-test.ts","./src/app/api/agents/connection-test/route.ts","./src/app/api/agents/local-cli/route.ts","./src/core/api-provider-models.ts","./src/app/api/agents/provider-models/route.ts","./src/core/types.ts","./src/core/paths.ts","./src/core/pricing.ts","./src/core/parser.ts","./node_modules/dayjs/locale/types.d.ts","./node_modules/dayjs/locale/index.d.ts","./node_modules/dayjs/index.d.ts","./src/core/discovery.ts","./src/core/fast-discovery.ts","./src/core/cost-tracker.ts","./src/app/api/devlog/route.ts","./src/app/api/devlog/daily/route.ts","./src/app/api/devlog/stream/route.ts","./src/app/api/health/route.ts","./src/lib/api-utils.ts","./node_modules/readdirp/esm/index.d.ts","./node_modules/chokidar/esm/handler.d.ts","./node_modules/chokidar/esm/index.d.ts","./src/core/file-watcher.ts","./src/app/api/locks/route.ts","./src/app/api/projects/route.ts","./src/app/api/projects/active/route.ts","./src/core/report-evidence.ts","./src/core/report-skill.ts","./src/core/report-summary.ts","./node_modules/toml/index.d.ts","./src/core/config.ts","./src/core/report-summary-store.ts","./src/app/api/reports/route.ts","./src/app/api/reports/export/route.ts","./src/app/api/sessions/route.ts","./src/app/api/sessions/[id]/route.ts","./src/app/api/sessions/[id]/messages/route.ts","./src/core/session-stream-dedupe.ts","./src/core/session-stream-replay.ts","./src/app/api/sessions/[id]/stream/route.ts","./src/core/vcc.ts","./src/app/api/sessions/[id]/vcc/route.ts","./src/core/task-readiness.ts","./src/app/api/tasks/route.ts","./src/app/api/tasks/[id]/route.ts","./src/app/api/tasks/[id]/execute/route.ts","./src/app/api/tasks/[id]/pr/route.ts","./src/core/task-retry.ts","./src/app/api/tasks/[id]/retry/route.ts","./src/app/api/tasks/reorder/route.ts","./src/app/api/worktrees/route.ts","./src/app/api/worktrees/[name]/route.ts","./node_modules/commander/typings/index.d.ts","./node_modules/commander/typings/esm.d.mts","./node_modules/chalk/source/vendor/ansi-styles/index.d.ts","./node_modules/chalk/source/vendor/supports-color/index.d.ts","./node_modules/chalk/source/index.d.ts","./node_modules/cli-spinners/index.d.ts","./node_modules/ora/index.d.ts","./node_modules/dayjs/plugin/relativetime.d.ts","./node_modules/dayjs/plugin/istoday.d.ts","./node_modules/dayjs/plugin/isyesterday.d.ts","./src/cli/utils/format.ts","./src/cli/utils/output.ts","./src/cli/commands/shared.ts","./src/core/cache.ts","./src/cli/commands/dashboard.ts","./src/cli/commands/init.ts","./src/cli/commands/sessions.ts","./src/cli/commands/show.ts","./src/cli/commands/today.ts","./src/cli/commands/search.ts","./src/cli/commands/stats.ts","./src/cli/commands/cost.ts","./src/cli/commands/statusline.ts","./src/cli/commands/setup-statusline.ts","./src/cli/commands/setup-tmux.ts","./src/cli/commands/serve.ts","./src/cli/cli.ts","./src/cli/index.ts","./src/cli/utils/paths.ts","./src/components/kanban/task-card-actions.ts","./src/hooks/use-agent-settings.ts","./src/hooks/use-session-chat.ts","./node_modules/clsx/clsx.d.mts","./node_modules/class-variance-authority/dist/types.d.ts","./node_modules/class-variance-authority/dist/index.d.ts","./node_modules/@radix-ui/react-accessible-icon/dist/index.d.mts","./node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-collapsible/dist/index.d.mts","./node_modules/@radix-ui/react-accordion/dist/index.d.mts","./node_modules/@radix-ui/react-dismissable-layer/dist/index.d.mts","./node_modules/@radix-ui/react-focus-scope/dist/index.d.mts","./node_modules/@radix-ui/react-portal/dist/index.d.mts","./node_modules/@radix-ui/react-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-alert-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-aspect-ratio/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/dist/index.d.mts","./node_modules/@radix-ui/react-checkbox/dist/index.d.mts","./node_modules/@radix-ui/react-arrow/dist/index.d.mts","./node_modules/@radix-ui/rect/dist/index.d.mts","./node_modules/@radix-ui/react-popper/dist/index.d.mts","./node_modules/@radix-ui/react-roving-focus/dist/index.d.mts","./node_modules/@radix-ui/react-menu/dist/index.d.mts","./node_modules/@radix-ui/react-context-menu/dist/index.d.mts","./node_modules/@radix-ui/react-direction/dist/index.d.mts","./node_modules/@radix-ui/react-dropdown-menu/dist/index.d.mts","./node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-form/dist/index.d.mts","./node_modules/@radix-ui/react-hover-card/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-menubar/dist/index.d.mts","./node_modules/@radix-ui/react-visually-hidden/dist/index.d.mts","./node_modules/@radix-ui/react-navigation-menu/dist/index.d.mts","./node_modules/@radix-ui/react-one-time-password-field/dist/index.d.mts","./node_modules/@radix-ui/react-password-toggle-field/dist/index.d.mts","./node_modules/@radix-ui/react-popover/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-progress/dist/index.d.mts","./node_modules/@radix-ui/react-radio-group/dist/index.d.mts","./node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","./node_modules/@radix-ui/react-select/dist/index.d.mts","./node_modules/radix-ui/node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-slider/dist/index.d.mts","./node_modules/@radix-ui/react-slot/dist/index.d.mts","./node_modules/@radix-ui/react-switch/dist/index.d.mts","./node_modules/@radix-ui/react-tabs/dist/index.d.mts","./node_modules/@radix-ui/react-toast/dist/index.d.mts","./node_modules/@radix-ui/react-toggle/dist/index.d.mts","./node_modules/@radix-ui/react-toggle-group/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/dist/index.d.mts","./node_modules/@radix-ui/react-tooltip/dist/index.d.mts","./node_modules/radix-ui/dist/index.d.mts","./node_modules/tailwind-merge/dist/types.d.ts","./src/core/dashboard-utils.ts","./src/components/ui/button.tsx","./src/components/ui/textarea.tsx","./node_modules/@types/unist/index.d.ts","./node_modules/@types/hast/index.d.ts","./node_modules/vfile-message/lib/index.d.ts","./node_modules/vfile-message/index.d.ts","./node_modules/vfile/lib/index.d.ts","./node_modules/vfile/index.d.ts","./node_modules/unified/lib/callable-instance.d.ts","./node_modules/trough/lib/index.d.ts","./node_modules/trough/index.d.ts","./node_modules/unified/lib/index.d.ts","./node_modules/unified/index.d.ts","./node_modules/@types/mdast/index.d.ts","./node_modules/mdast-util-to-hast/lib/state.d.ts","./node_modules/mdast-util-to-hast/lib/footer.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/blockquote.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/delete.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/emphasis.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/footnote-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/heading.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/html.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/inline-code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list-item.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/paragraph.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/root.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/strong.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-cell.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-row.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/text.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/thematic-break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/index.d.ts","./node_modules/mdast-util-to-hast/lib/index.d.ts","./node_modules/mdast-util-to-hast/index.d.ts","./node_modules/remark-rehype/lib/index.d.ts","./node_modules/remark-rehype/index.d.ts","./node_modules/react-markdown/lib/index.d.ts","./node_modules/react-markdown/index.d.ts","./node_modules/lucide-react/dist/lucide-react.d.ts","./src/components/sessions/session-chat.tsx","./src/components/sessions/session-chat.test.ts","./src/core/control-plane-state.ts","./src/core/cost-analytics.ts","./src/core/db-schema-registry.ts","./src/core/db-pool.ts","./src/core/devlog-dashboard.ts","./src/core/lock-manager.ts","./src/core/task-retry-request.ts","./src/core/__tests__/agent-connection-test.test.ts","./src/core/__tests__/agent-presets.test.ts","./src/core/__tests__/agent-settings.test.ts","./src/core/__tests__/api-provider-models.test.ts","./src/core/__tests__/api-provider-runtime.test.ts","./src/core/__tests__/test-helpers.ts","./src/core/__tests__/api-session-runtime.test.ts","./src/core/__tests__/control-plane-protocol.test.ts","./src/core/__tests__/control-plane-state.test.ts","./src/core/__tests__/cost-analytics.test.ts","./src/core/__tests__/cost-tracker.test.ts","./src/core/__tests__/db-migrations.test.ts","./src/core/__tests__/db-pool.test.ts","./src/core/__tests__/db-schema-registry.test.ts","./src/core/__tests__/db-schema.test.ts","./src/core/__tests__/devlog-dashboard.test.ts","./src/core/__tests__/local-cli-agents.test.ts","./src/core/__tests__/lock-manager.test.ts","./src/core/__tests__/parser-cost.test.ts","./src/core/__tests__/pricing.test.ts","./src/core/__tests__/process-manager-health.test.ts","./src/core/__tests__/quality-gates.test.ts","./src/core/__tests__/report-evidence.test.ts","./src/core/__tests__/report-skill.test.ts","./src/core/__tests__/report-summary-store.test.ts","./src/core/__tests__/report-summary.test.ts","./src/core/__tests__/session-runtime-auth.test.ts","./src/core/__tests__/session-stream-dedupe.test.ts","./src/core/__tests__/session-stream-replay.test.ts","./src/core/__tests__/smoke.test.ts","./src/core/__tests__/stream-manager.test.ts","./src/core/__tests__/task-card-actions.test.ts","./scripts/task-launch-e2e-config.mjs","./src/core/__tests__/task-launch-e2e-config.test.ts","./src/core/__tests__/task-lifecycle.test.ts","./src/core/__tests__/task-readiness.test.ts","./src/core/__tests__/task-retry-request.test.ts","./src/core/__tests__/task-retry.test.ts","./src/hooks/use-cost-report.ts","./src/hooks/use-daily-costs.ts","./src/hooks/use-devlog.ts","./src/hooks/use-locks.ts","./src/hooks/use-projects.ts","./src/hooks/use-sessions.ts","./src/hooks/use-task-analytics.ts","./src/hooks/use-task-sessions.ts","./src/hooks/use-tasks.ts","./src/hooks/use-today-stats.ts","./src/hooks/use-vcc.ts","./src/hooks/use-worktrees.ts","./node_modules/next/dist/compiled/@next/font/dist/types.d.ts","./node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","./node_modules/next/font/google/index.d.ts","./src/components/ui/tooltip.tsx","./src/components/ui/select.tsx","./src/components/layout/sidebar.tsx","./src/components/layout/header.tsx","./src/components/ui/alert.tsx","./src/components/locks/conflict-alert.tsx","./src/app/layout.tsx","./src/components/dashboard/conflict-alert-bar.tsx","./src/components/dashboard/activity-metrics.tsx","./node_modules/@types/d3-time/index.d.ts","./node_modules/@types/d3-scale/index.d.ts","./node_modules/victory-vendor/d3-scale.d.ts","./node_modules/recharts/types/shape/dot.d.ts","./node_modules/recharts/types/component/text.d.ts","./node_modules/recharts/types/zindex/zindexlayer.d.ts","./node_modules/recharts/types/cartesian/getcartesianposition.d.ts","./node_modules/recharts/types/component/label.d.ts","./node_modules/recharts/types/cartesian/cartesianaxis.d.ts","./node_modules/recharts/types/util/scale/customscaledefinition.d.ts","./node_modules/redux/dist/redux.d.ts","./node_modules/@reduxjs/toolkit/node_modules/immer/dist/immer.d.ts","./node_modules/reselect/dist/reselect.d.ts","./node_modules/redux-thunk/dist/redux-thunk.d.ts","./node_modules/@reduxjs/toolkit/dist/uncheckedindexed.ts","./node_modules/@reduxjs/toolkit/dist/index.d.mts","./node_modules/recharts/types/state/cartesianaxisslice.d.ts","./node_modules/recharts/types/synchronisation/types.d.ts","./node_modules/recharts/types/chart/types.d.ts","./node_modules/recharts/types/component/defaulttooltipcontent.d.ts","./node_modules/recharts/types/context/brushupdatecontext.d.ts","./node_modules/recharts/types/state/chartdataslice.d.ts","./node_modules/recharts/types/state/types/linesettings.d.ts","./node_modules/recharts/types/state/types/scattersettings.d.ts","./node_modules/@types/d3-path/index.d.ts","./node_modules/@types/d3-shape/index.d.ts","./node_modules/victory-vendor/d3-shape.d.ts","./node_modules/recharts/types/shape/curve.d.ts","./node_modules/recharts/types/component/labellist.d.ts","./node_modules/recharts/types/component/defaultlegendcontent.d.ts","./node_modules/recharts/types/util/payload/getuniqpayload.d.ts","./node_modules/recharts/types/util/useelementoffset.d.ts","./node_modules/recharts/types/component/legend.d.ts","./node_modules/recharts/types/state/legendslice.d.ts","./node_modules/recharts/types/state/types/stackedgraphicalitem.d.ts","./node_modules/recharts/types/util/stacks/stacktypes.d.ts","./node_modules/recharts/types/util/scale/rechartsscale.d.ts","./node_modules/recharts/types/util/chartutils.d.ts","./node_modules/recharts/types/state/selectors/areaselectors.d.ts","./node_modules/recharts/types/cartesian/area.d.ts","./node_modules/recharts/types/state/types/areasettings.d.ts","./node_modules/recharts/types/animation/easing.d.ts","./node_modules/recharts/types/shape/rectangle.d.ts","./node_modules/recharts/types/cartesian/bar.d.ts","./node_modules/recharts/types/util/barutils.d.ts","./node_modules/recharts/types/state/types/barsettings.d.ts","./node_modules/recharts/types/state/types/radialbarsettings.d.ts","./node_modules/recharts/types/util/svgpropertiesnoevents.d.ts","./node_modules/recharts/types/util/useuniqueid.d.ts","./node_modules/recharts/types/state/types/piesettings.d.ts","./node_modules/recharts/types/state/types/radarsettings.d.ts","./node_modules/recharts/types/state/graphicalitemsslice.d.ts","./node_modules/recharts/types/state/tooltipslice.d.ts","./node_modules/recharts/types/state/optionsslice.d.ts","./node_modules/recharts/types/state/layoutslice.d.ts","./node_modules/immer/dist/immer.d.ts","./node_modules/recharts/types/util/ifoverflow.d.ts","./node_modules/recharts/types/util/resolvedefaultprops.d.ts","./node_modules/recharts/types/cartesian/referenceline.d.ts","./node_modules/recharts/types/state/referenceelementsslice.d.ts","./node_modules/recharts/types/state/brushslice.d.ts","./node_modules/recharts/types/state/rootpropsslice.d.ts","./node_modules/recharts/types/state/polaraxisslice.d.ts","./node_modules/recharts/types/state/polaroptionsslice.d.ts","./node_modules/recharts/types/cartesian/line.d.ts","./node_modules/recharts/types/util/constants.d.ts","./node_modules/recharts/types/util/scatterutils.d.ts","./node_modules/recharts/types/shape/symbols.d.ts","./node_modules/recharts/types/cartesian/scatter.d.ts","./node_modules/recharts/types/cartesian/errorbar.d.ts","./node_modules/recharts/types/state/errorbarslice.d.ts","./node_modules/recharts/types/state/zindexslice.d.ts","./node_modules/recharts/types/state/eventsettingsslice.d.ts","./node_modules/recharts/types/state/renderedticksslice.d.ts","./node_modules/recharts/types/state/store.d.ts","./node_modules/recharts/types/cartesian/getticks.d.ts","./node_modules/recharts/types/cartesian/cartesiangrid.d.ts","./node_modules/recharts/types/state/selectors/combiners/combinedisplayedstackeddata.d.ts","./node_modules/recharts/types/state/selectors/selecttooltipaxistype.d.ts","./node_modules/recharts/types/types.d.ts","./node_modules/recharts/types/hooks.d.ts","./node_modules/recharts/types/state/selectors/axisselectors.d.ts","./node_modules/recharts/types/component/dots.d.ts","./node_modules/recharts/types/util/typeddatakey.d.ts","./node_modules/recharts/types/util/types.d.ts","./node_modules/recharts/types/container/surface.d.ts","./node_modules/recharts/types/container/layer.d.ts","./node_modules/recharts/types/component/cursor.d.ts","./node_modules/recharts/types/component/tooltip.d.ts","./node_modules/recharts/types/component/responsivecontainer.d.ts","./node_modules/recharts/types/component/cell.d.ts","./node_modules/recharts/types/component/customized.d.ts","./node_modules/recharts/types/shape/sector.d.ts","./node_modules/recharts/types/shape/polygon.d.ts","./node_modules/recharts/types/shape/cross.d.ts","./node_modules/recharts/types/polar/polargrid.d.ts","./node_modules/recharts/types/polar/defaultpolarradiusaxisprops.d.ts","./node_modules/recharts/types/polar/polarradiusaxis.d.ts","./node_modules/recharts/types/polar/defaultpolarangleaxisprops.d.ts","./node_modules/recharts/types/polar/polarangleaxis.d.ts","./node_modules/recharts/types/context/tooltipcontext.d.ts","./node_modules/recharts/types/polar/pie.d.ts","./node_modules/recharts/types/polar/radar.d.ts","./node_modules/recharts/types/util/radialbarutils.d.ts","./node_modules/recharts/types/polar/radialbar.d.ts","./node_modules/recharts/types/cartesian/brush.d.ts","./node_modules/recharts/types/cartesian/referencedot.d.ts","./node_modules/recharts/types/util/excludeeventprops.d.ts","./node_modules/recharts/types/util/svgpropertiesandevents.d.ts","./node_modules/recharts/types/cartesian/referencearea.d.ts","./node_modules/recharts/types/cartesian/barstack.d.ts","./node_modules/recharts/types/cartesian/xaxis.d.ts","./node_modules/recharts/types/cartesian/yaxis.d.ts","./node_modules/recharts/types/cartesian/zaxis.d.ts","./node_modules/recharts/types/chart/linechart.d.ts","./node_modules/recharts/types/chart/barchart.d.ts","./node_modules/recharts/types/chart/piechart.d.ts","./node_modules/recharts/types/chart/treemap.d.ts","./node_modules/recharts/types/chart/sankey.d.ts","./node_modules/recharts/types/chart/radarchart.d.ts","./node_modules/recharts/types/chart/scatterchart.d.ts","./node_modules/recharts/types/chart/areachart.d.ts","./node_modules/recharts/types/chart/radialbarchart.d.ts","./node_modules/recharts/types/chart/composedchart.d.ts","./node_modules/recharts/types/chart/sunburstchart.d.ts","./node_modules/recharts/types/shape/trapezoid.d.ts","./node_modules/recharts/types/cartesian/funnel.d.ts","./node_modules/recharts/types/chart/funnelchart.d.ts","./node_modules/recharts/types/util/global.d.ts","./node_modules/recharts/types/zindex/defaultzindexes.d.ts","./node_modules/decimal.js-light/decimal.d.ts","./node_modules/recharts/types/util/scale/getnicetickvalues.d.ts","./node_modules/recharts/types/context/chartlayoutcontext.d.ts","./node_modules/recharts/types/util/getrelativecoordinate.d.ts","./node_modules/recharts/types/util/createcartesiancharts.d.ts","./node_modules/recharts/types/util/createpolarcharts.d.ts","./node_modules/recharts/types/index.d.ts","./src/components/dashboard/velocity-chart.tsx","./src/components/ui/scroll-area.tsx","./src/components/dashboard/activity-feed.tsx","./src/components/dashboard/project-progress.tsx","./src/components/dashboard/command-stream.tsx","./src/components/dashboard/cost-card.tsx","./src/components/ui/skeleton.tsx","./src/app/page.tsx","./src/components/ui/card.tsx","./src/components/devlog/cost-chart.tsx","./src/components/ui/badge.tsx","./src/components/ui/progress.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/devlog/cost-usage-dashboard.tsx","./src/app/devlog/page.tsx","./src/components/locks/lock-table.tsx","./src/app/locks/page.tsx","./src/components/ui/input.tsx","./src/app/reports/page.tsx","./src/components/sessions/process-indicator.tsx","./src/components/ui/label.tsx","./src/components/sessions/agent-selector.tsx","./src/components/sessions/session-card.tsx","./src/components/ui/dialog.tsx","./src/components/sessions/launch-dialog.tsx","./src/app/sessions/page.tsx","./src/components/sessions/session-vcc.tsx","./src/app/sessions/[id]/page.tsx","./src/app/settings/page.tsx","./node_modules/css-box-model/src/index.d.ts","./node_modules/@hello-pangea/dnd/dist/dnd.d.ts","./src/components/kanban/task-card.tsx","./src/components/kanban/column.tsx","./src/components/kanban/create-task-dialog.tsx","./src/components/kanban/task-review-panel.tsx","./src/components/kanban/task-detail-dialog.tsx","./src/components/kanban/board.tsx","./src/app/tasks/page.tsx","./src/components/worktrees/worktree-card.tsx","./src/components/worktrees/diff-viewer.tsx","./src/app/worktrees/page.tsx","./src/components/dashboard/active-sessions-panel.tsx","./src/components/dashboard/command-stats-bar.tsx","./src/components/dashboard/parallel-worktrees-panel.tsx","./src/components/dashboard/task-quick-view.tsx","./src/components/devlog/stats-grid.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/separator.tsx","./src/components/ui/switch.tsx","./node_modules/@types/d3-array/index.d.ts","./node_modules/@types/d3-color/index.d.ts","./node_modules/@types/d3-ease/index.d.ts","./node_modules/@types/d3-interpolate/index.d.ts","./node_modules/@types/d3-timer/index.d.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/debug/index.d.ts","./node_modules/@types/estree-jsx/node_modules/@types/estree/index.d.ts","./node_modules/@types/estree-jsx/index.d.ts","./node_modules/@types/set-cookie-parser/index.d.ts","./node_modules/@types/statuses/index.d.ts","./node_modules/@types/use-sync-external-store/index.d.ts","./node_modules/@types/validate-npm-package-name/index.d.ts"],"fileIdsList":[[74,121,486,487],[74,121,247,486],[62,74,121,938],[74,121],[62,74,121],[62,74,121,605,606,607],[62,74,121,605,612],[62,74,121,606],[62,74,121,605,606],[62,74,121,247,605,606],[62,74,121,605,606,621],[62,74,121,605,606,609,610,611],[62,74,121,247,605,606,625],[62,74,121,605,606,609,611,619],[62,74,121,605,606,609,610,611,619,620],[62,74,121,247,605,606,620,621],[62,74,121,605,606,609,630],[62,74,121,606,620],[62,74,121,605,606,609,610,611,619],[62,74,121,605,606,617,618],[62,74,121,605,606,620],[62,74,121,605,606,609],[62,74,121,605,606,620,645],[62,74,121,605,606,620,639,646],[74,121,781,782,783,784,785],[74,121,247],[74,121,169],[74,121,959],[74,121,771],[74,121,795],[74,121,963],[74,121,965,966],[74,121,655],[74,118,121],[74,120,121],[121],[74,121,126,154],[74,121,122,127,132,140,151,162],[74,121,122,123,132,140],[69,70,71,74,121],[74,121,124,163],[74,121,125,126,133,141],[74,121,126,151,159],[74,121,127,129,132,140],[74,120,121,128],[74,121,129,130],[74,121,131,132],[74,120,121,132],[74,121,132,133,134,151,162],[74,121,132,133,134,147,151,154],[74,121,129,132,135,140,151,162],[74,121,132,133,135,136,140,151,159,162],[74,121,135,137,151,159,162],[72,73,74,75,76,77,78,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[74,121,132,138],[74,121,139,162,167],[74,121,129,132,140,151],[74,121,141],[74,121,142],[74,120,121,143],[74,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168],[74,121,145],[74,121,146],[74,121,132,147,148],[74,121,147,149,163,165],[74,121,132,151,152,154],[74,121,153,154],[74,121,151,152],[74,121,154],[74,121,155],[74,118,121,151,156],[74,121,132,157,158],[74,121,157,158],[74,121,126,140,151,159],[74,121,160],[74,121,140,161],[74,121,135,146,162],[74,121,126,163],[74,121,151,164],[74,121,139,165],[74,121,166],[74,116,121],[74,116,121,132,134,143,151,154,162,165,167],[74,121,151,168],[62,66,74,121,170,171,172,174,433,479],[62,66,74,121,170,171,172,173,390,433,479],[62,66,74,121,170,171,173,174,433,479],[62,74,121,174,390,391],[62,74,121,174,390],[62,66,74,121,171,172,173,174,433,479],[62,66,74,121,170,172,173,174,433,479],[60,61,74,121],[74,121,135,169],[74,121,571,572],[74,121,161],[74,121,133,536,538],[74,121,132,133,536,537],[74,121,601,602],[74,121,601],[74,121,569],[74,121,526],[74,121,525],[74,121,527,576,578],[74,121,527,576,577],[74,121,527,577,578],[74,121,656,666,667,668,692,693,694],[74,121,656,667,694],[74,121,656,666,667,694],[74,121,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691],[74,121,656,660,666,668,694],[74,121,436],[74,121,438,439,440,441],[74,121,179,181,185,196,386,416,429],[74,121,181,191,192,193,195,429],[74,121,181,228,230,232,233,236,429,431],[74,121,181,185,187,188,189,219,314,386,406,407,415,429,431],[74,121,429],[74,121,192,284,395,404,424],[74,121,181],[74,121,175,284,424],[74,121,238],[74,121,237,429],[74,121,135,384,395,484],[74,121,135,352,364,404,423],[74,121,135,295],[74,121,409],[74,121,408,409,410],[74,121,408],[68,74,121,135,175,181,185,188,190,192,196,197,210,211,238,314,325,405,416,429,433],[74,121,179,181,194,228,229,234,235,429,484],[74,121,194,484],[74,121,179,211,339,429,484],[74,121,484],[74,121,181,194,195,484],[74,121,231,484],[74,121,197,406,414],[74,121,146,247,424],[74,121,247,424],[62,74,121,247],[62,74,121,356],[74,121,282,292,293,424,461,468],[74,121,281,401,462,463,464,465,467],[74,121,400],[74,121,400,401],[74,121,219,284,285,289],[74,121,284],[74,121,284,288,290],[74,121,284,285,286,287],[74,121,466],[62,74,121,182,455],[62,74,121,162],[62,74,121,194,274],[62,74,121,194,416],[74,121,272,276],[62,74,121,273,435],[74,121,759],[62,66,74,121,135,169,170,171,172,173,174,433,477,478],[74,121,135],[74,121,135,185,218,270,315,336,338,411,412,416,429,430],[74,121,210,413],[74,121,433],[74,121,180],[62,74,121,341,354,363,373,375,423],[74,121,146,341,354,372,373,374,423,483],[74,121,366,367,368,369,370,371],[74,121,368],[74,121,372],[74,121,245,246,247,249],[62,74,121,239,240,241,242,248],[74,121,245,248],[74,121,243],[74,121,244],[62,74,121,247,273,435],[62,74,121,247,434,435],[62,74,121,247,435],[74,121,315,418],[74,121,418],[74,121,135,430,435],[74,121,360],[74,120,121,359],[74,121,220,284,301,338,347,350,352,353,394,423,426,430],[74,121,266,284,381],[74,121,352,423],[62,74,121,352,357,358,360,361,362,363,364,365,376,377,378,379,380,382,383,423,424,484],[74,121,346],[74,121,135,146,182,218,221,242,267,268,315,325,336,337,394,417,429,430,431,433,484],[74,121,423],[74,120,121,192,268,325,349,417,419,420,421,422,430],[74,121,352],[74,120,121,218,255,301,342,343,344,345,346,347,348,350,351,423,424],[74,121,135,255,256,342,430,431],[74,121,192,315,325,338,417,423,430],[74,121,135,429,431],[74,121,135,151,426,430,431],[74,121,135,146,162,175,185,194,220,221,223,252,257,262,266,267,268,270,299,301,303,306,308,311,312,313,314,336,338,416,417,424,426,429,430,431],[74,121,135,151],[74,121,181,182,183,190,426,427,428,433,435,484],[74,121,179,429],[74,121,251],[74,121,135,151,162,213,236,238,239,240,241,242,249,250,484],[74,121,146,162,175,213,228,261,262,263,299,300,301,306,314,315,321,324,326,336,338,417,424,426,429],[74,121,190,197,210,314,325,417,429],[74,121,135,162,182,185,301,319,426,429],[74,121,340],[74,121,135,251,322,323,333],[74,121,426,429],[74,121,347,349],[74,121,268,301,416,435],[74,121,135,146,224,228,300,306,321,324,328,426],[74,121,135,197,210,228,329],[74,121,181,223,331,416,429],[74,121,135,162,242,429],[74,121,135,194,222,223,224,233,251,330,332,416,429],[68,74,121,135,268,335,433,435],[74,121,298,336],[74,121,135,146,162,185,196,197,210,220,221,257,261,262,263,267,299,300,301,303,315,316,318,320,336,338,416,417,424,425,426,435],[74,121,135,151,197,321,327,333,426],[74,121,200,201,202,203,204,205,206,207,208,209],[74,121,252,307],[74,121,309],[74,121,307],[74,121,309,310],[74,121,135,185,188,218,219,430],[74,121,135,146,180,182,220,266,267,268,269,297,336,426,431,433,435],[74,121,135,146,162,184,219,269,301,347,417,425,430],[74,121,342],[74,121,343],[74,121,284,314,394],[74,121,344],[74,121,212,216],[74,121,135,185,212,220],[74,121,215,216],[74,121,217],[74,121,212,213],[74,121,212,264],[74,121,212],[74,121,252,305,425],[74,121,304],[74,121,213,424,425],[74,121,302,425],[74,121,213,424],[74,121,394],[74,121,185,214,220,268,284,301,335,338,341,347,354,355,385,386,389,393,416,426,430],[74,121,277,280,282,283,292,293],[62,74,121,172,174,247,387,388],[62,74,121,172,174,247,387,388,392],[74,121,403],[74,121,192,256,268,335,338,352,360,364,396,397,398,399,401,402,405,416,423,429],[74,121,292],[74,121,135,297],[74,121,297],[74,121,135,220,265,270,294,296,335,426,433,435],[74,121,277,278,279,280,282,283,292,293,434],[68,74,121,135,146,162,212,213,221,267,268,301,333,334,336,416,417,426,429,430,433],[74,121,256,258,261,417],[74,121,135,252,429],[74,121,255,352],[74,121,254],[74,121,256,257],[74,121,253,255,429],[74,121,135,184,256,258,259,260,429,430],[62,74,121,284,291,424],[74,121,177,178],[62,74,121,182],[62,74,121,281,424],[62,68,74,121,267,268,433,435],[74,121,182,455,456],[62,74,121,276],[62,74,121,146,162,180,235,271,273,275,435],[74,121,194,424,430],[74,121,317,424],[62,74,121,133,135,146,179,180,230,276,433,434],[62,74,121,170,171,172,173,174,433,479],[62,63,64,65,66,74,121],[74,121,126],[74,121,225,226,227],[74,121,225],[62,66,74,121,135,137,146,169,170,171,172,173,174,175,180,221,328,372,431,432,435,479],[74,121,443],[74,121,445],[74,121,447],[74,121,760],[74,121,449],[74,121,451,452,453],[74,121,457],[67,74,121,437,442,444,446,448,450,454,458,460,470,471,473,482,483,484,485],[74,121,459],[74,121,469],[74,121,273],[74,121,472],[74,120,121,256,258,259,261,474,475,476,479,480,481],[74,121,574],[74,121,604,607,608,611,612,613,614,615,616,622,623,624,625,626,627,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,648,649],[74,121,697],[62,74,121,656,665,694,696],[74,121,133,151],[62,74,121,776,787,792,798,799,806,808,809,811,852,855],[62,74,121,776,787,792,797,799,808,812,813,815,816,852,855],[62,74,121,808,813,857],[62,74,121,791,855],[62,74,121,775,776,778,787,855],[62,74,121,776,787,808,846,855],[62,74,121,776,814,835,839,855],[62,74,121,799,822,823,855,896],[74,121,775,855],[74,121,787,855],[62,74,121,776,787,792,798,799,852,855],[62,74,121,776,778,813,827,879],[62,74,121,774,776,778,827],[62,74,121,776,778,807,827,828,855],[62,74,121,776,787,790,794,798,799,823,837,838,852,855],[62,74,121,780,787,855],[62,74,121,780,787,852,855],[62,74,121,855],[62,74,121,813,823,855],[62,74,121,775,823,855],[62,74,121,823,855],[62,74,121,788],[62,74,121,776,823,855],[62,74,121,774,776,855],[62,74,121,775,776,777,855],[62,74,121,775,776,778,855,907],[62,74,121,800,801,802],[62,74,121,787,789,790,801,823,855,858],[74,121,845,855],[74,121,787,788,807,850,852,855],[74,121,774,775,776,778,779,780,787,788,790,798,799,800,803,807,810,813,814,823,827,829,835,837,838,839,840,847,850,851,852,855,856,857,859,860,861,862,863,864,865,866,868,870,872,873,874,875,876,877,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,902,903,904,905,906],[62,74,121,776,792,799,818,820,855,871],[62,74,121,776,780,787,828,855,869],[62,74,121,776,787],[62,74,121,776,780,787,828,855,867],[62,74,121,776,799,807,819,828,855],[62,74,121,776,787,792,797,799,808,852,855,863,871,874],[62,74,121,797,855],[62,74,121,812,855],[74,121,781,786,855],[74,121,779,780,781,786,852,855],[74,121,781,786,791],[74,121,781,786,822,840,855],[74,121,781,786,787,792,793,794,811,816,817,820,821,855],[74,121,781,786,800,803,855],[74,121,781,786,823,855],[74,121,781,786,787],[74,121,781,786],[74,121,781,786,787,826,827,829],[74,121,781,786,787,826,855],[74,121,781,786,788,810,855],[74,121,806,822,845,855],[74,121,787,792,805,806,807,822,830,833,841,845,847,848,849,851,855],[74,121,787,792,805,806],[74,121,845],[74,121,786,787,792,804,822,823,824,825,830,831,832,833,834,841,842,843,844],[74,121,781,786,787,789,790,822,855],[74,121,792,805,810,822,855],[74,121,805,815,822],[74,121,792,822,855],[62,74,121,790,818,819,822,855],[74,121,822],[74,121,805,822],[74,121,790,792,822,855],[74,121,808,822,855],[74,121,823,855],[62,74,121,813,814,855],[74,121,790,797,804,806,807,823,852,855],[62,74,121,810,814,835,839,855,882,883,884,897],[62,74,121,855,868,870,872,873,875],[74,121,855],[62,74,121,875],[74,121,787,855,901],[74,121,780,855],[62,74,121,822,836,839,855],[74,121,797,805,808,822],[62,74,121,818,878],[62,74,121,773,774,775,778,779,780,787,788,789,792,810,818,852,853,854,907],[74,121,781],[74,121,694,695],[74,121,656,660,665,666,694],[74,121,491,492],[74,121,151,169],[74,121,662],[74,121,490,492,493],[74,88,92,121,162],[74,88,121,151,162],[74,83,121],[74,85,88,121,159,162],[74,121,140,159],[74,83,121,169],[74,85,88,121,140,162],[74,80,81,84,87,121,132,151,162],[74,88,95,121],[74,80,86,121],[74,88,109,110,121],[74,84,88,121,154,162,169],[74,109,121,169],[74,82,83,121,169],[74,88,121],[74,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,121],[74,88,103,121],[74,88,95,96,121],[74,86,88,96,97,121],[74,87,121],[74,80,83,88,121],[74,88,92,96,97,121],[74,92,121],[74,86,88,91,121,162],[74,80,85,88,95,121],[74,121,151],[74,83,88,109,121,167,169],[74,121,660,664],[74,121,655,660,661,663,665],[74,121,657],[74,121,658,659],[74,121,655,658,660],[74,121,772],[74,121,796],[74,121,126,133,141,142,247],[74,121,247,482,499,516],[74,121,247,482,498,514],[74,121,247,482,499,519],[74,121,134,142,247,482,522,524,527],[74,121,247,482,522,528,529,530],[74,121,247,482,506],[74,121,247,482,504],[74,121,247,482,504,505,535,539],[74,121,247,482,509],[74,121,247,482,545,548],[74,121,247,482,504,505],[74,121,247,482,499,504,505,515],[74,121,247,482,504,506,535,554,555],[74,121,247,482,504,509,557],[74,121,126,247,482,499,502,504,505,512,515,535],[74,121,126,247,482,499,502,504,505,509,510,511,512,515,535,539,559],[74,121,122,163,247,482,504,505,509,510,535,557],[74,121,126,247,482,499,502,504,505,509,510,512,515,535,557,564],[74,121,247,482,504,505,559],[74,121,247,482,504,505,535,559],[74,121,247,482,510],[74,121,247,482,510,535],[74,121,247,917,922],[74,121,247,486,761,762,764,765,767],[74,121,247,750,767,914,924],[62,74,121,247,653,699,749,750,751,752,753,755,769,770,908,910,911,912,913,914],[62,74,121,247,460,545,653,699,914,916,918,921,926],[62,74,121,247,470,505,652,653,699,700,702,918,928,930,935],[74,121,247,559,699,752,914,931,933],[62,74,121,247,497,498,599,652,653,699,762,763,916,926,929],[74,121,247,945],[62,74,121,247,653,699,758,914,926,929,932,947,948],[74,121,247,521,570,573,579,580,583,584,585,586,587,588,589,590,591,592,593,594],[74,121,247,521,530,573,575,579,580],[74,121,133,247,521,522,528,547,573,575,579,580,581,582],[74,121,133,247,521,522,528,547,573,575,579,580],[74,121,247,521,528,547,573,575,579,580,581],[74,121,122,133,142,247,521,573],[74,121,122,133,141,142,162,247,528,547,573,582],[74,121,122,133,141,142,162,247,573],[74,121,247,521],[74,121,247,521,524,528,547,573,575,579,580],[74,121,247,521,527,528,547,573,575,577,579,580,582],[74,121,133,141,142,247,521,527,529,547,582],[74,121,247,521,527,528,547,573,575,577,579,580,581],[74,121,247,521,522,523,524,528,529,547,579,580,582],[74,121,247,527,573,576,577,578],[74,121,141,142,247],[74,121,247,460,505,527,576,699,909,918],[74,121,247,652,699,753,909],[74,121,247,505,652,699],[74,121,247,505,699,918],[62,74,121,247,505,506,652,753,909],[62,74,121,247,653,699],[74,121,247,505,652],[74,121,247,460,505,699,916,918],[74,121,247,652],[62,74,121,247,499,505,652,653,699,755,909,918,939,942,944],[74,121,247,652,753,907],[62,74,121,247,653,748,907,914,916],[62,74,121,247,530,653,699,703,747,914,916,918,919,920,921],[74,121,247,505,699,916],[62,74,121,247,460,470,499,505,511,599,653,699,754,755,914,939,941,942,944],[74,121,247,505,652,918,939,940],[62,74,121,247,505,653,654,699,763,926,929,932],[74,121,247,505,511,559],[74,121,247,470,505,527,559,576,598,652,653,699,702,916,918,939],[62,74,121,247,470,499,502,505,511,599,652,653,654,699,702,763,918,926,929,930,932,943],[62,74,121,247,470,505,599,653,654,699,708,909,929],[74,121,247,470],[74,121,247,460,470,652,699,751,763],[74,121,247,699,750,766],[74,121,247,505,653,699,918,920],[74,121,247,497,498,499,502,763,918,929],[62,74,121,247,470,499,502,505,599,653,654,699,763,929,930,932],[74,121,247,505,652,699,918],[74,121,247,460,505,559,653,699,702,916,918,928,930],[74,119,121,156,247,600,700],[62,74,121,247,498,505,559,600,652,653,654,698,699],[62,74,121,247,652,653,699,757,909,926],[62,74,121,247,603,652],[62,74,121,247,603,650,652],[62,74,121,247,652],[62,74,121,247,650,652,653,699],[62,74,121,247,650,652,699],[62,74,121,247,650,652],[62,74,121,247,909,914,916,921],[74,121,247,505,653,699,916,918],[74,119,121,132,151,156,247,499,516],[74,119,121,156,247,502,505,508,512],[74,119,121,156,247,498],[74,119,121,156,247,499,519],[74,119,121,156,247,499,500],[74,119,121,156,247,506,513,714],[74,119,121,156,247,501,503,507],[74,119,121,156,247,702],[74,119,121,156,247,530,703],[74,119,121,134,141,142,156,247,530],[74,119,121,156,247,501,504],[74,119,121,133,142,156,247,705,714],[74,119,121,156,247,501,704],[74,119,121,156,247,501,504,714],[74,119,121,156,247,706],[74,119,121,156,247,514],[74,119,121,156,247,707,714],[74,119,121,134,141,142,156,247,524],[74,119,121,156,247,523],[74,119,121,156,247,499,506,515],[74,119,121,133,156,247],[74,119,121,156,247,543,545],[74,119,121,156,247,544],[74,119,121,134,141,142,156,247,545,548],[74,119,121,156,247,545],[74,119,121,156,247,499],[74,119,121,156,247,506,554],[74,119,121,156,247,555,714],[74,119,121,156,247],[74,119,121,156,247,506],[74,119,121,156,247,505,598],[74,119,121,156,247,741],[74,119,121,156,247,511,512,714],[74,119,121,156,247,559],[74,119,121,156,247,708],[74,119,121,156,247,499,502,505,564],[74,121,133,141,142,247,501,503],[74,121,122,134,141,142,247,499,500,515],[74,121,247,497,499],[74,121,247,499,500],[74,121,247,498,499],[74,121,247,499,500,501,506,512],[74,121,133,142,247,521,522,527],[74,121,133,142,247,521,522,546],[74,121,126,247,501,505],[74,121,247,505],[74,121,247,530],[74,121,133,134,141,142,147,247,521,527,528],[74,121,247,601,651],[74,121,133,141,142,247,501,503,504,704],[74,121,247,497,498,499,502],[74,121,133,142,247,497,498,499,501,502,503],[74,121,133,134,142,247,521,522,524,527],[74,121,134,142,247,521,522,524,527],[74,121,142,247,504,506,538],[74,121,122,133,142,247,497],[74,121,247,501],[74,121,133,147,247,521,523],[74,121,122,126,133,147,247,497,499,500,504,506,507,512,513,514],[74,121,133,142,247,508],[74,121,247,505,545],[74,121,126,133,142,247,504,509,545,547],[74,121,247,505,543,544],[74,121,247,497,498],[74,121,247,506],[74,121,247,501,506],[74,121,247,499,501,502,504,505,508,510,511],[74,121,247,499],[74,121,247,499,502,505,508,512],[74,121,122,133,142,163,247,522],[74,121,122,142,163,247,505,509],[62,74,121,247,498],[62,74,121,247,530],[62,74,121,247,532],[62,74,121,247,505,706],[62,74,121,247,505],[62,74,121,247,498,599],[62,74,121,247,499,505,506],[62,74,121,247,505,527],[62,74,121,247,505,559,752],[74,121,247,494]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","impliedFormat":1},{"version":"2de7636e6fbb9e54a61a38bcb7505b94ec5be61197fe9e840cff629ca920c4bc","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e20d899c28ca26a2a7afc98beaa69e63ff7fba0a8bc47b4e3bf3ede5e09e424","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"085f552d005479e2e6a7311cdbbe5d8c55c497b4d19274285df161ee9684cd9c","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"007faacc9268357caa21d24169f3f3f2497af3e9241308df2d89f6e6d9bb3f2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"5c9b31919ea1cb350a7ae5e71c9ced8f11723e4fa258a8cc8d16ae46edd623c7","impliedFormat":1},{"version":"4aa42ce8383b45823b3a1d3811c0fdd5f939f90254bc4874124393febbaf89f6","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"3677988e03b749874eb9c1aa8dc88cd77b6005e5c4c39d821cda7b80d5388619","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"f4625edcb57b37b84506e8b276eb59ca30d31f88c6656d29d4e90e3bc58e69df","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"e2a37ac938c4bede5bb284b9d2d042da299528f1e61f6f57538f1bd37d760869","impliedFormat":1},{"version":"76def37aff8e3a051cf406e10340ffba0f28b6991c5d987474cc11137796e1eb","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"594fe24fc54645ab6ccb9dba15d3a35963a73a395b2ef0375ea34bf181ccfd63","impliedFormat":1},{"version":"7cb0ee103671d1e201cd53dda12bc1cd0a35f1c63d6102720c6eeb322cb8e17e","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"ad37fb4be61c1035b68f532b7220f4e8236cf245381ce3b90ac15449ecfe7305","impliedFormat":1},{"version":"93436bd74c66baba229bfefe1314d122c01f0d4c1d9e35081a0c4f0470ac1a6c","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"304b44b1e97dd4c94697c3313df89a578dca4930a104454c99863f1784a54357","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"97e5ccc7bb88419005cbdf812243a5b3186cdef81b608540acabe1be163fc3e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"6b3453eebd474cc8acf6d759f1668e6ce7425a565e2996a20b644c72916ecf75","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"89cd3444e389e42c56fd0d072afef31387e7f4107651afd2c03950f22dc36f77","impliedFormat":1},{"version":"7f2aa4d4989a82530aaac3f72b3dceca90e9c25bee0b1a327e8a08a1262435ad","impliedFormat":1},{"version":"e39a304f882598138a8022106cb8de332abbbb87f3fee71c5ca6b525c11c51fc","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"fcdf3e40e4a01b9a4b70931b8b51476b210c511924fcfe3f0dae19c4d52f1a54","impliedFormat":1},{"version":"345c4327b637d34a15aba4b7091eb068d6ab40a3dedaab9f00986253c9704e53","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"2b5b70d7782fe028487a80a1c214e67bd610532b9f978b78fa60f5b4a359f77e","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"7580e62139cb2b44a0270c8d01abcbfcba2819a02514a527342447fa69b34ef1","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"7e6ac205dcb9714f708354fd863bffa45cee90740706cc64b3b39b23ebb84744","impliedFormat":1},{"version":"61dc6e3ac78d64aa864eedd0a208b97b5887cc99c5ba65c03287bf57d83b1eb9","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"f730b468deecf26188ad62ee8950dc29aa2aea9543bb08ed714c3db019359fd9","impliedFormat":1},{"version":"933aee906d42ea2c53b6892192a8127745f2ec81a90695df4024308ba35a8ff4","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"144bc326e90b894d1ec78a2af3ffb2eb3733f4d96761db0ca0b6239a8285f972","impliedFormat":1},{"version":"a3e3f0efcae272ab8ee3298e4e819f7d9dd9ff411101f45444877e77cfeca9a4","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"71d9eb4c4e99456b78ae182fb20a5dfc20eb1667f091dbb9335b3c017dd1c783","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"30e6520444df1a004f46fdc8096f3fe06f7bbd93d09c53ada9dcdde59919ccca","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"a58beefce74db00dbb60eb5a4bb0c6726fb94c7797c721f629142c0ae9c94306","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"502fa5863df08b806dbf33c54bee8c19f7e2ad466785c0fc35465d7c5ff80995","impliedFormat":1},{"version":"c91a2d08601a1547ffef326201be26db94356f38693bb18db622ae5e9b3d7c92","impliedFormat":1},{"version":"888cda0fa66d7f74e985a3f7b1af1f64b8ff03eb3d5e80d051c3cbdeb7f32ab7","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"9586918b63f24124a5ca1d0cc2979821a8a57f514781f09fc5aa9cae6d7c0138","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"55095860901097726220b6923e35a812afdd49242a1246d7b0942ee7eb34c6e4","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"1a6e6ba8a07b74e3ad237717c0299d453f9ceb795dbc2f697d1f2dd07cb782d2","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"190da5eac6478d61ab9731ab2146fbc0164af2117a363013249b7e7992f1cccb","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"a46dba563f70f32f9e45ae015f3de979225f668075d7a427f874e0f6db584991","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"622694a8522b46f6310c2a9b5d2530dde1e2854cb5829354e6d1ff8f371cf469","impliedFormat":1},{"version":"d24ff95760ea2dfcc7c57d0e269356984e7046b7e0b745c80fea71559f15bdd8","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"13c1b657932e827a7ed510395d94fc8b743b9d053ab95b7cd829b2bc46fb06db","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"078131f3a722a8ad3fc0b724cd3497176513cdcb41c80f96a3acbda2a143b58e","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"9e155d2255348d950b1f65643fb26c0f14f5109daf8bd9ee24a866ad0a743648","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"7a883e9c84e720810f86ef4388f54938a65caa0f4d181a64e9255e847a7c9f51","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d408d6f32de8d1aba2ff4a20f1aa6a6edd7d92c997f63b90f8ad3f9017cf5e46","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"9d622ea608d43eb463c0c4538fd5baa794bc18ea0bb8e96cd2ab6fd483d55fe2","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},"7ad303e40d4fddf44f156129e397511953a71481c5cfd86b1862649aaaf240cc",{"version":"896029d28fe0ea1a074fbf66ad012258106857abe17bef77ae3a6799da44392a","signature":"435a1e418e8338be3f39614b96b81a9aa2700bc8c27bc6b98f064ff9ce17c363"},{"version":"161c8e0690c46021506e32fda85956d785b70f309ae97011fd27374c065cac9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"ee70b8037ecdf0de6c04f35277f253663a536d7e38f1539d270e4e916d225a3f","affectsGlobalScope":true,"impliedFormat":1},{"version":"89dcbbf69b16cd94043e16c7fbcfa04256577ec98bb8ae894833d2a922394db4","impliedFormat":1},{"version":"e6ceaf94d57c812d95e43d034e093add2456041eace95ece0e24ccacd462b370","impliedFormat":1},{"version":"fbc85cbcecf5fa4ea4a191c0111e5b94abd1d1dd430da8ae234bf68791e6f924","signature":"c79e164f36bcd986b89191e7212fea08a4536681fe42f300bb7b769105bea6eb"},{"version":"3089753b3495b233d75e9767471b4377e302549440ce639c985726143e34bd0a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"4e13c6840d96ed4a0b3d742b1647e021dc75b75e8dbdef9b8f16aeb2e99261bf","signature":"a98d08f68d152b6e6325b429ca3097622a95addb7de4bffa05c90d969ebece2a"},{"version":"8205ca4dc1428e527ebb6955192a95c55e7d0a1e59f830235daf046ac4a92a6d","signature":"b7e48606f14a7edd37d4f38660d8ed5043d55f2b86f586eb8b59dbc1931aea3b"},{"version":"ee48a8d85234cf40231fd7b20473b81867afacec2878ba2504f105a9dea09768","signature":"8bdbd4bb3c4756c214e41936f22e82093859f821b2199b955378e980e27500b5"},{"version":"ece50a5a72f023a34ed04696f7a0eca1e4b462cf3adcb44f9d230621fb2551d7","signature":"ba7ee1b50566e863bfe1917ac8cc06e9b70ef1f24ccdf825edbbd1f40a914d7b"},{"version":"c2a6a737189ced24ffe0634e9239b087e4c26378d0490f95141b9b9b042b746c","impliedFormat":1},{"version":"84cea0272b7811cd6e625a9826d66da23f7d7fb88e7a4686f1fbe716f1480343","signature":"282908d98ec8b09fb71997248db545cbb578c35adf688b9b4571e9510edc6335"},{"version":"42d2462ad0068ef41bf79de0e84b376c22c8cb24536ca4f9ba16e11291834a27","signature":"6a5e5b4dd51823c21a15cac63e45d618d8db44c8b2e7703c81e2a61f248051ee"},{"version":"aae0554ccdcb552b0ed9ff497b3add3f479d53875d83480cc35da4b21bd16585","signature":"2a131c4bfe5f003dc439e586126f26f00076b47b5608d7615a437f63cc77ab1f"},{"version":"7ee8ee2f3075fabfe9405bd422dad65e6905728346787aa1700be70dc0fcadae","signature":"02c0ca146be46014dca516639a87d3b314112fc77105d161153bd8906a8b6ee3"},{"version":"5a1b120c29e5e19dbe919b9516be4f01a7114286f36ffd6406921fb970893ff3","signature":"9e8c81dc4776f75cdd38c33228ad1623fc74b35c4af0d6bfc657be2eba7d393b"},{"version":"11f286ac427e5b936f50f7a86a2b9516115893dc435b44a366b0f34b6b7b7575","signature":"58b58ab79586978978e090b8c5819c4d3ff3caf2013209425059c1c58410ef61"},{"version":"de7adf4e7f759c4a67ff3263a6153da1f6430de5b74880f72d2d144d2b808b46","signature":"0969bc09967b5a8190c1e4aef30390183931ceccf15a33a350f2f9b350e20405"},{"version":"3cdcae5627195bf2e408a9b3ad6b5ad12cc3cfe97067093c78e225a0c9657efe","signature":"838901a64f07bdc319de0545c72bf7b68b6072e0294bc7d909bf5514802c6bcb"},{"version":"064d41a76c5fb28fea1ced5d69eef753abb2606a6ed9b0e6aae7bcb1f8a2de16","signature":"d6ef02ea1b5ebbe6a2f6bc3dde449c14a8991ead846e042472da76198f26043d"},{"version":"b44a218ce201d9b66da66d74ef0772b2fed5f3e37feac9e07cbd9fa10add42af","signature":"3a123df657d800aab8653e3d75bf4e17b5f020d722cd76298ada9d32100c5813"},{"version":"8a0ee34e33ccc2a5065c4296e5ebc25680330f9920f8891bb3ddf18a7cbbf94d","signature":"cc2f661fcac3b9cc3abe5f58745a0535a6a79fc956bc4c5e671708209ab3092a"},{"version":"c2e5464034e12991927d41e847702cfccdab2e19612850732b3bdcac4e605d7d","signature":"46e8721d320adb34eb354c039c9ecf861c9437dbdf6e93a76aa5c6ec1b1e4592"},{"version":"eb35f108a4aea0719c2f22ac63d64d990a4fb6d9604312724fdaf9f24448318d","signature":"d2b85632543fcc67ca56e7b1d3c7323b92a87869a3da6676bdab33630f87dbd2"},{"version":"acdb18c805ff51b242c94a0ffcc89066e6c7ac412402de4356b046736b871996","signature":"3c7ac46a6dc465e8cec543431071d01228a27b3aedcfa37213da388a87332528"},{"version":"71ef994015bd874194e69e501e795192ee0c3a2d445380b1d2e29c628c751d73","signature":"d536c5277d6390e48d87a554e76a5dfeff91f23e58ccdd88c1190bb553c01c67"},{"version":"bb36c976b899d491019a61e0c79e33d51b28e94eae73a0a764dce6e0fa5e1f9f","signature":"d9536033fbe0727223159286b386c9db11275685428e76fcc2509aa3ad0bf061"},{"version":"7808015d490d6f480607e972bd62115d703bcca8f56b9a5422116e0b7cf098c8","signature":"23ba3edb61e57caf69bc6b3ebec598833a7c90885a57f2c3236bd8ec6909d62b"},{"version":"c5fa7e05f204f68c0062e194b7331feda1ab50827bf2cb9f06faebd7fce3cb30","signature":"1f62b14e7fc4f2866901afcfff02c6a41d0e8e246cb5dd94d0313c54872be214"},{"version":"bde9208c200b91f38f36970418e0f0cce41040de1eb11e3a70d23a27315ab18d","signature":"39018d85740d9944633be6830f3fe14429d837d3c8a72b048568ce2da4a2b719"},{"version":"321227784adf046a4455b9d91350b4b4a74988553d8c2895865a7390b1502c23","signature":"c7cba78b1c634f298b89052cc5d98edebf19c1634420b1f93b57330fef20c3bd"},{"version":"89cd727fc52a37e95bf25bd7abdd10d3648b511c67fbf9242bf0564bf4a2a842","signature":"0c5a7bd8cb9f42f74fc3c536cc2533896d5a82bcf8546fb2b86c1bcd596c3536"},{"version":"6a31d173cfde3d9986dd4909306c7ca8cf47aa22fc89f3fbf12cd73d7385e93c","signature":"1dd2f9a8fb2c74aef91a3c9360ebef06d88369263155c4d9cc8ed1dd9598670f"},{"version":"07480ae60ce4c90edc118caff5627b31c75cfbbf4f6b0e97c00f482ff635fab6","signature":"fd55a26eab3ee5a7a8311bbc9ea822124b7374ccfef0fe8b0dc4ea078c8a496c"},{"version":"73a0ee6395819b063df4b148211985f2e1442945c1a057204cf4cf6281760dc3","affectsGlobalScope":true,"impliedFormat":1},{"version":"d05d8c67116dceafc62e691c47ac89f8f10cf7313cd1b2fb4fe801c2bf1bb1a7","impliedFormat":1},{"version":"3c5bb5207df7095882400323d692957e90ec17323ccff5fd5f29a1ecf3b165d0","impliedFormat":1},{"version":"719703fbab3da4f46ee965b90bccaac9786238f260ee0e866d49b562d26b03f8","signature":"84fc9bb843f5a125016309a55aeb82a44a5faf63d654a097816fcc7857a1aec3"},{"version":"083b0dcd0a26ea9daa44618173c1c2dff0b5022f7801337b339a9a690cbe303b","signature":"fa727886ea6eb3453cc057409131f88890db43007749a63306e48a7ce027922b"},{"version":"616e9b9381023b6322f1e09ae83f2e6898a38a45f160a7db8681c8a79142bf64","signature":"182496053544eb635dc562ca810f767d18dab869ef8372b2a4783258a8f299ec"},{"version":"443bb5ebce851045fc2d690258b4fea92f7d4f0d8234a16e3263d25055005dad","signature":"bb256ae9e02db9d8a6f612e066fa9aef968d5e5eeee2baf7d01cd0b258702ecf"},{"version":"bf892c8c7c39afed1aa807e6d7c36fec665c9c9f4a21e6cd36d7300332de4f7f","signature":"6962cb0990055fbdc2e3f813cef6453bac4c9eba5b73e250c05f49b8d66498a0"},{"version":"4d8a60c3fa94a972ef099532155c89baa3aabb857e19d1939e71369ae58a094a","signature":"1bc7659a2929580d056216836af2ebb09cfa5643b8f62be9270896f44b105ad9"},{"version":"22abee0b8236a1eab0d0296159bf712e4916e3a5d76735e393b285365ff7dfdd","signature":"46399842ff7b76890e1127b6ec73a79ed2d69b8b394851a908b55be8beb58fe7"},{"version":"cc6fe493ff1e9ce823b13585bc4e1ad2c60b471046bddb84956f06e4d9a1585c","signature":"672477cc4f32bdfd1e75a801478059e8bc102fc3c1ef2f7f44da464c304f5b15"},{"version":"d3a6e1ff56a0a760b1b36eb34925042a8148d8e0ab4c2d28fcbdbf40fb5a8acc","impliedFormat":99},{"version":"839114ddc4236b8304df6a6c7cc6784913b7c69a63afd4ecb36fc5c9c57276fc","impliedFormat":99},{"version":"cc4ecb6238b32248c6b58577a2ac2a6223c002c1a9e3f1f9424a89f44aa84f0a","impliedFormat":99},{"version":"d8347f1c1b3cb0542d3b9c035a3fc60b29530a44bab488feb27a3b24cee8c065","signature":"81e132e180c63ffc69178404ceb384bbd3a47fc915abbc7e88c5f19f4c5717d8"},{"version":"2351254578af067c5c3de36ac1c095c32f5b7d33505443594ec31f6399977a5d","signature":"6249f8b0992e774d58f01ae26fc78fc6963a18e591d81f1b4796270be4a143ca"},{"version":"0626216ce593b877ca3ac04db6b233ae581f2197f41a71a493b99da15e51add0","signature":"33bf3a06bbb4e7ec8217b6118ca6732bfc04e145199d6bb17f3453a837082121"},{"version":"e3f68a251d60cc53a6ab436bbb24bce62077a9f2250082f08f6b5f957dab114a","signature":"73d4c5c33eb9165262da4729597ef1717fafc51fa3cb23f753857168376b1eab"},{"version":"22168d53c2e3c2986ef56cad977085f33c95db5616d90e162009711157b071c4","signature":"8ca14311c7d5504f1b3506f80c0d4b385e9b8984337f8b3270fc8d6c04d25d40"},{"version":"75696038b82900374a5d8b780f134a1c26b03be5fc95e0b25abff173bee069ca","signature":"8defb2d3b9421f6a48df252b8b5ee4f2d1b1cbbefe794372c924bf5c330ffe33"},{"version":"e66008fdc63ae4b54fb3e1030e5cf8525ab926e8aa76be070dc1d193d52dd074","signature":"5c0f72f1a5914ec88db0d2e68caa11d6a144a154f66daac31b0e310cf1da4f1f"},{"version":"a7fe7e88c50608567af53c49d3c59ea5f33bf5f59126d67b2a25f85eb41297ba","impliedFormat":1},{"version":"f10c64fd1a065596d04631f3eaface87359b3da5d06ece45137a53657d24e523","signature":"a2d6bbcc199f5f70c8d0fc7bdf577d2189409bd3f83da2a2d5220a74e2e04d80"},{"version":"c80c30bb55afd9a38ac2cb35212470dc93e2d51ee8f8ec7d42889517762cd658","signature":"26b20b434bf21e20f876227be18514d204e43817bbc865c8bf30f2118f7457fc"},{"version":"3fbe7b0b33133b3cff1f4e363a3e8c4ab4fa6346cc6e0eb1073ad0aff58535ac","signature":"0c8ef79f6661c043621cf75e56fd25fa8718a50242b03ecef6ee742da12bd090"},{"version":"db168d3cebe2ff3c764684f185ee6955b060c9ad998ad0091f0445784ba88b5c","signature":"bd2399cd593fbb535c9c3105d269a98f6f5c04059118c59a8c700a054ec20a18"},{"version":"59a855be68480bd53538d00c98c5355d81612e27aeea9dc68c5e1aa10639b91e","signature":"77427b0241410e39f5997f26b72c444b39904411ac6f413fdec4e1164e70aa3b"},{"version":"eb31a82b62a1374e7b617621f1af237a1369d3b790858382e9bd0eed7aca29b5","signature":"b7efab64cd4f45586c10cbfde96b261b08b1139943284369ba382f65eabaded0"},{"version":"0754157c4a498a0e88d926dc22e93898d92c56759d953aad7c70bafb3365f47d","signature":"d0a4235e3ba99197db4079c6428cf8cac17c049e93efb4f550b2530249f23bfe"},{"version":"9148369c2ba2f572d8168fc49345a7ce018f073fa80af1676e3fd1561b53d98c","signature":"40073698daed81244321d44f44ba481cb455b63f47ef64c3221b9f59c278cd89"},{"version":"642fa4123e483c2ff8a124f1fb173cf54b65b0a0c3ef0c65ec26fcd75dda1334","signature":"76628f9c32d52252cf3e52c008adf06a17d026065666428003fd26b3f8f0024c"},{"version":"89f603501c16183eae53fd86cdd2b5c571a2e542fbc799bb1fe3ec77d2241894","signature":"f4d94baa358570780b5a0cd2ce17d316cbbb052f8af73886097e1887e0c886d8"},{"version":"b1a727e164d34dbb28abb169a65f64c06794a4510c9d7692ae623e2c3a74c232","signature":"bff8a9bddb4caeb0dc332257702534d8d1bcaa10d9ef1e59702fc34bb4a7edc8"},{"version":"2d8c9ab1cd4b4f7bc0892aa46b312a232cffb34c3a6d86e88eb47eeecea40798","signature":"a29577f56463e87465bb6c5cd567e4569f0a280f3fe2e8984e2329a1bfa64d70"},{"version":"45c21560252f13688151642207a7de67f042f83f83614f810049156906ad6196","signature":"77fdba5a43cef2c4963cd66eadd9069da67640ca2f3dd149dc7b6ffde430821f"},{"version":"92ef2d97f513c33e567897b2ea13f3145fa2000f5cc6a98e69e312056f6f1838","signature":"e7bc947a0cbaf1c8ceb25c68d7fc1e47ef227979fa2016de673443fce086d0bb"},{"version":"58594dd6b618f5093f8cd996b633a9da685026461d1275f0789b39dec83a4fea","signature":"65dd0550fc2c70c6a351a9d5b5081ad0937a4aa417cef5ea4ffe04b5d1c120a9"},{"version":"0b43b217aa5ae501669ffcb221ac707f688b52a0497d0fe990066b2402f7c46f","signature":"e80d9ad040eeb9ca11dbcf12dacfa9ebe42a45ab6af9d83984b4933d35569744"},{"version":"2a041f09032ad520e75adfb33ffe9c82a09f0935de2c98bd71b1fd23a2db3005","signature":"9b5ebdfeae990b52a0a5e911c89269ae730cfa7c130cdbeb7510f14cf43cc28c"},{"version":"f8a06873478d758aae483c3335cef932b649131495f51c0028ce855426ad7887","signature":"6ba7ed0feb6c91d143fd61bd7befee463781cffe613f51f10c95e3a8b67d3b38"},{"version":"4e43c0c7121377a60bbb6a00bf5d543ec3f388487bb982cbb6e3af6dfdbb9a82","signature":"b97cd80e9759326d8b1db4a7898830b3f5441ccdf63e26ee2250b7d5f0077967"},{"version":"92acc45d403b8931c35712650356998a4c559b61a7699e86fa426886fab46223","signature":"4714cdef481ecb8b34c1a38ead3eb32605a3cefe08191c901e2d9a7c1d163f1a"},{"version":"840bf8e79872842982837cec72b2fa05c52a4341d6b4c98a5af2e3ad2657c5fa","signature":"24b2b5814f5dd0dd5fbb2a02fb104b72fcb33e55c35da0e2e7208307dd3c57b5"},{"version":"4f0c2a4fba22353838d27c00ddc1c74287c365efc874f8a9c2e178d877f12fff","signature":"ef898929c80d986df99390f94c9361c9fd4d9523639d157462dcd7d78b4db4af"},{"version":"0237580177f1a858ab125992af8a6dfc29268fe7d4bac5308b9f462f88b0cd31","impliedFormat":1},{"version":"b124c0624b15412ace7d54644ade38d7a69db7e25488a1a4d2a8df6e11696538","impliedFormat":99},{"version":"acfed6cc001e7f7f26d2ba42222a180ba669bb966d4dd9cb4ad5596516061b13","impliedFormat":99},{"version":"f61a4dc92450609c353738f0a2daebf8cae71b24716dbd952456d80b1e1a48b6","impliedFormat":99},{"version":"f3f76db6e76bc76d13cc4bfa10e1f74390b8ebe279535f62243e8d8acd919314","impliedFormat":99},{"version":"6bbb2e249520ec6ddd60e970972603d415f0a0ef44c7329e4b8f56dc2442da09","impliedFormat":99},{"version":"01cbbe1afa317defb741e97195bca78f96bce416f8ad03bb5a505316fba0ebb7","impliedFormat":99},{"version":"f684f2969931de8fb9a5164f8c8f51aaea4025f4eede98406a17642a605c2842","impliedFormat":1},{"version":"1aaededa2ff9719b5f1babb9c91ca8b680f51308ffa941a8baf2bc7a8940847e","impliedFormat":1},{"version":"19836a9526f2b7907bf9853af6667e76b974a5fb4a1705e3da7398d81eb7c7c1","impliedFormat":1},{"version":"146467ad43eccd04ddf1bdc9f7d98b86d2a132ac8a1573c1dc617489b554c436","signature":"2a5ab1d06d7a34e3dfc113ae8eba0b0b7efb7722fd5ecc19609738df2e3f1254"},{"version":"21f0a0bf1f09910cb34e530f1f61de01e96202ac67ad2660c180f8b43cb3f71a","signature":"030b5066f051b8ad33f71d138330bbc9ca7e7bc3852628e1fe5d2489d46d5d1c"},{"version":"7dbcdfa015725c7acbf74c03622685206f0330314660f5264d12dfab8a5c7b3d","signature":"10c8a10a00f03277f63ceab7ccda176fd96c142d609b6698e2bae840156bb81c"},{"version":"ed9c530c419af5933502594eed3004323682d954b898b3869ef56dae2ffac812","signature":"e4a372c58fc244dd2c569b99d6826d15584f84a3bcd2bfb76275c7c7c925c006"},{"version":"e4a7c2fefd0332fe13c34b497fd66e17c90d44933a502cbca5b853e23d34d8f2","signature":"07c7c2b7885e36bd98fc3d6a7c3d1e2e875147ef5546068a7b4557be5ee095a0"},{"version":"c5fdd9c8e3bc60c2fdae1a08bf9d36fa10672ba1b809cd5247f8c2c3b1d7c0c7","signature":"0b6836209ae43f5e56c4ee02f8a344758c5f502bbfee5fd516288495eecb37c6"},{"version":"6e6cbd39f93e459928d38b8488a176a9d9171ad4e581046620e24649c07df8aa","signature":"35959aea174d4144d793794707a4aa69d5675560c18e4e99a13b8bfd24c1b0fc"},{"version":"42717344a2d06e652f34c1a84c72b90e459ed72a640ece06c795ba15461cd89c","signature":"b3bef511f0768499382b84cda3e57c5d5f10c513116eb07e1ff305e1542656c2"},{"version":"879ee3ccbbf281e2594146867cedbed1ef2e08cba54c2f91415a42abd37c672c","signature":"bd940ee2d5f8da90d42a4cf5ef6435e105579847d517289ea91a0e4a4804ea26"},{"version":"9c20a12cd439f9def1933afa603e62b4e4e5852b943edc6999a221a56b7221ed","signature":"c4722259f5df8d68e91b08973ac1e53e7147bc841c2f0801fad33c1dc9e740ff"},{"version":"0a9ad266281a2127d544ef8827e8875d57a87c9b32e187adc39b97e2f56752f3","signature":"a4b1838e84b65a10c5c55dd5fc019c60e9ccbb16cd157914aa7e2f650819fe71"},{"version":"7e6883262d6683c1e5df6c886c09d0857d155c3eeeb9e758d573644c6e16dd53","signature":"a173ff24b3a88b126d152e3d9179e12ef67c6ef069417e03fe3036c753d6855a"},{"version":"bd10320d21f0e28849b8d264e6582777c904f0c91188c73e2818696172463094","signature":"b16b8fdd04399d7253b8853942810ac691d4d500481b49f4c1006e78727a86d4"},{"version":"783572e420a5af94543ba13053a00e10d06a034ddc947683990ceba5fcab672d","signature":"df988206a8451bb8696826aaf14288b34c590b9087c82f25ecf51246a2e44ddb"},{"version":"4be282ddc333a83c0558a1053ac699bb3d136f5b306b80d1deedc0b563f18f07","signature":"f602b0ebd3946afdc02c557b46a37c139a689b4fe8a7a9504b4bc4d59f47c04d"},{"version":"61d636743dc58831038abb0f19e28b6912bdf7bc52694ef974969984cca10021","signature":"afbd3867a4f5cd5697753353b1f64c06c756dc911dbaab0b7998955618c53500"},{"version":"11ca0c9a390757847f541eaed6d0cbcaeee758e3ca3b38c9ded3c78fe648fd67","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},"d651aff31ecc868e6262a675de501b30d74ce28ce26c3d3ace39e12240be4469",{"version":"89cd727fc52a37e95bf25bd7abdd10d3648b511c67fbf9242bf0564bf4a2a842","signature":"0c5a7bd8cb9f42f74fc3c536cc2533896d5a82bcf8546fb2b86c1bcd596c3536"},{"version":"26420fb924cf95559be4ffaf736b41556bcf64d7fbe59e76942f730750bb9be7","signature":"58c67d7c8bae32ecb816fa4379e1062df1a98425d2840e6eebed54ad4bf7f782"},{"version":"0c9865fd7d059a2f5f39d5c675812444b7cc77fb50547c083896ff31e20618a6","signature":"939408125293a83e7ef5118b5d2878d790b4e82016a6b560c15e6de08656ec64"},{"version":"837dd0b38de00f0b73c3d4c1fd00e59aeaa90d8491864b1041bb8f6cbf6a22bf","signature":"603dbc3f655d534a2147aa29a48b26951e64694dcaefb4f4745427c39c725166"},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"024829c0b317972acf4f871bf701525f81896ad74015f1a52d46ae6036205cb9","impliedFormat":99},{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"0943a6e4e026d0de8a4969ee975a7283e0627bf41aa4635d8502f6f24365ac9b","impliedFormat":99},{"version":"1461efc4aefd3e999244f238f59c9b9753a7e3dfede923ebe2b4a11d6e13a0d0","impliedFormat":99},{"version":"7ec047b73f621c526468517fea779fec2007dd05baa880989def59126c98ef79","impliedFormat":99},{"version":"8dd450de6d756cee0761f277c6dc58b0b5a66b8c274b980949318b8cad26d712","impliedFormat":99},{"version":"904d6ad970b6bd825449480488a73d9b98432357ab38cf8d31ffd651ae376ff5","impliedFormat":99},{"version":"dfcf16e716338e9fe8cf790ac7756f61c85b83b699861df970661e97bf482692","impliedFormat":99},{"version":"31c30cc54e8c3da37c8e2e40e5658471f65915df22d348990d1601901e8c9ff3","impliedFormat":99},{"version":"36d8011f1437aecf0e6e88677d933e4fb3403557f086f4ac00c5a4cb6d028ac2","impliedFormat":99},{"version":"8085954ba165e611c6230596078063627f3656fed3fb68ad1e36a414c4d7599a","impliedFormat":99},{"version":"2c57db2bf2dbd9e8ef4853be7257d62a1cb72845f7b976bb4ee827d362675f96","impliedFormat":99},{"version":"6b5f886fe41e2e767168e491fe6048398ed6439d44e006d9f51cc31265f08978","impliedFormat":99},{"version":"56a87e37f91f5625eb7d5f8394904f3f1e2a90fb08f347161dc94f1ae586bdd0","impliedFormat":99},{"version":"6b863463764ae572b9ada405bf77aac37b5e5089a3ab420d0862e4471051393b","impliedFormat":99},{"version":"68b6a7501a56babd7bcd840e0d638ee7ec582f1e70b3c36ebf32e5e5836913c8","impliedFormat":99},{"version":"89783bd45ab35df55203b522f8271500189c3526976af533a599a86caaf31362","impliedFormat":99},{"version":"6da2e0928bdab05861abc4e4abebea0c7cf0b67e25374ba35a94df2269563dd8","impliedFormat":99},{"version":"e7b00bec016013bcde74268d837a8b57173951add2b23c8fd12ffe57f204d88f","impliedFormat":99},{"version":"26e6c521a290630ea31f0205a46a87cab35faac96e2b30606f37bae7bcda4f9d","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"044047026c70439867589d8596ffe417b56158a1f054034f590166dd793b676b","impliedFormat":99},{"version":"89ad9a4e8044299f356f38879a1c2176bc60c997519b442c92cc5a70b731a360","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"fd4f58cd6b5fc8ce8af0d04bfef5142f15c4bafaac9a9899c6daa056f10bb517","impliedFormat":99},{"version":"2a00cea77767cb26393ee6f972fd32941249a0d65b246bfcb20a780a2b919a21","impliedFormat":99},{"version":"440cb5b34e06fabe3dcb13a3f77b98d771bf696857c8e97ce170b4f345f8a26b","impliedFormat":99},{"version":"5bc7f0946c94e23765bd1b8f62dc3ab65d7716285ca7cf45609f57777ddb436f","impliedFormat":99},{"version":"7d5a5e603a68faea3d978630a84cacad7668f11e14164c4dd10224fa1e210f56","impliedFormat":99},{"version":"2535fc1a5fe64892783ff8f61321b181c24f824e688a4a05ae738da33466605b","impliedFormat":99},{"version":"cbfd5ef0c8fdb4983202252b5f5758a579f4500edc3b9ad413da60cffb5c3564","impliedFormat":99},{"version":"9f7a3c434912fd3feb87af4aabdf0d1b614152ecb5e7b2aa1fff3429879cdd51","impliedFormat":99},{"version":"99d1a601593495371e798da1850b52877bf63d0678f15722d5f048e404f002e4","impliedFormat":99},{"version":"1179ef8174e0e4a09d35576199df04803b1db17c0fb35b9326442884bc0b0cce","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"cc3738ba01d9af5ba1206a313896837ff8779791afcd9869e582783550f17f38","impliedFormat":99},{"version":"a80ec72f5e178862476deaeed532c305bdfcd3627014ae7ac2901356d794fc93","impliedFormat":99},{"version":"4a5aa16151dbec524bb043a5cbce2c3fec75957d175475c115a953aca53999a9","impliedFormat":99},{"version":"7a14bf21ae8a29d64c42173c08f026928daf418bed1b97b37ac4bb2aa197b89b","impliedFormat":99},{"version":"c5013d60cbff572255ccc87c314c39e198c8cc6c5aa7855db7a21b79e06a510f","impliedFormat":99},{"version":"69ec8d900cfec3d40e50490fedbbea5c1b49d32c38adbc236e73a3b8978c0b11","impliedFormat":99},{"version":"7fd629484ba6772b686885b443914655089246f75a13dd685845d0abae337671","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"13dcccb62e8537329ac0448f088ab16fe5b0bbed71e56906d28d202072759804","impliedFormat":99},{"version":"233267a4a036c64aee95f66a0d31e3e0ef048cccc57dd66f9cf87582b38691e4","impliedFormat":99},{"version":"ccb9fbe369885d02cf6c2b2948fb5060451565d37b04356bbe753807f98e0682","impliedFormat":99},{"version":"ff4bfe3c147eadc1b722a8ac9e4d350e66411b5c9022eabe5f4ada871c9adc41","impliedFormat":1},{"version":"7c8c3dfc0cdd370d44932828eb067ef771c8fe7996693221d5d4b90af6d54f2d","signature":"512960c0e955a2324b34354dac25e3e4d431a1af4cd33077935eda5e95c8b7e1"},{"version":"91d6b4d149d8b8e92e1b6f6a716aa9de4d4b0516b818fef43923100e045bb52c","signature":"5841c8f5528b440d77c0a80903e0d86b87e5e05c036889e89e7aefcdecc53988"},{"version":"28c5d9aa4362d575e7446e52a7e175c545c0aa0a7389d1a7f2cafad726a3b860","signature":"aa333ffa319c18796c9104d75082dfd218334109f702eb6e9ad369beac518833"},{"version":"89121c1bf2990f5219bfd802a3e7fc557de447c62058d6af68d6b6348d64499a","impliedFormat":1},{"version":"79b4369233a12c6fa4a07301ecb7085802c98f3a77cf9ab97eee27e1656f82e6","impliedFormat":1},{"version":"2b37ba54ec067598bf912d56fcb81f6d8ad86a045c757e79440bdef97b52fe1b","impliedFormat":99},{"version":"1bc9dd465634109668661f998485a32da369755d9f32b5a55ed64a525566c94b","impliedFormat":99},{"version":"5702b3c2f5d248290ed99419d77ca1cc3e6c29db5847172377659c50e6303768","impliedFormat":99},{"version":"9764b2eb5b4fc0b8951468fb3dbd6cd922d7752343ef5fbf1a7cd3dfcd54a75e","impliedFormat":99},{"version":"1fc2d3fe8f31c52c802c4dee6c0157c5a1d1f6be44ece83c49174e316cf931ad","impliedFormat":99},{"version":"dc4aae103a0c812121d9db1f7a5ea98231801ed405bf577d1c9c46a893177e36","impliedFormat":99},{"version":"106d3f40907ba68d2ad8ce143a68358bad476e1cc4a5c710c11c7dbaac878308","impliedFormat":99},{"version":"42ad582d92b058b88570d5be95393cf0a6c09a29ba9aa44609465b41d39d2534","impliedFormat":99},{"version":"36e051a1e0d2f2a808dbb164d846be09b5d98e8b782b37922a3b75f57ee66698","impliedFormat":99},{"version":"d4a22007b481fe2a2e6bfd3a42c00cd62d41edb36d30fc4697df2692e9891fc8","impliedFormat":1},{"version":"9d62e577adb05f5aafed137e747b3a1b26f8dce7b20f350d22f6fb3255a3c0ed","impliedFormat":99},{"version":"7ed92bcef308af6e3925b3b61c83ad6157a03ff15c7412cf325f24042fe5d363","impliedFormat":99},{"version":"3da9062d0c762c002b7ab88187d72e1978c0224db61832221edc8f4eb0b54414","impliedFormat":99},{"version":"84dbf6af43b0b5ad42c01e332fddf4c690038248140d7c4ccb74a424e9226d4d","impliedFormat":99},{"version":"00884fc0ea3731a9ffecffcde8b32e181b20e1039977a8ae93ae5bce3ab3d245","impliedFormat":99},{"version":"0bd8b6493d9bf244afe133ccb52d32d293de8d08d15437cca2089beed5f5a6b5","impliedFormat":99},{"version":"7fc3099c95752c6e7b0ea215915464c7203e835fcd6878210f2ce4f0dcbbfe67","impliedFormat":99},{"version":"83b5499dbc74ee1add93aef162f7d44b769dcef3a74afb5f80c70f9a5ce77cc0","impliedFormat":99},{"version":"8bf8b772b38fc4da471248320f49a2219c363a9669938c720e0e0a5a2531eabf","impliedFormat":99},{"version":"7da6e8c98eacf084c961e039255f7ebb9d97a43377e7eee2695cb77fec640c66","impliedFormat":99},{"version":"0b5b064c5145a48cd3e2a5d9528c63f49bac55aa4bc5f5b4e68a160066401375","impliedFormat":99},{"version":"702ff40d28906c05d9d60b23e646c2577ad1cc7cd177d5c0791255a2eab13c07","impliedFormat":99},{"version":"49ff0f30d6e757d865ae0b422103f42737234e624815eee2b7f523240aa0c8f8","impliedFormat":99},{"version":"0389aacf0ffd49a877a46814a21a4770f33fc33e99951a1584de866c8e971993","impliedFormat":99},{"version":"5cb7a51cf151c1056b61f078cf80b811e19787d1f29a33a2a6e4bf00334bbc10","impliedFormat":99},{"version":"215aa8915d707f97ad511b7abbf7eda51d3a7048e9a656955cf0dda767ae7db0","impliedFormat":99},{"version":"0d689a717fbef83da07ab4de33f83db5cbcec9bc4e3b04edb106c538a50a0210","impliedFormat":99},{"version":"d00bc73e8d1f4137f2f6238bb3aa2bbdad8573658cc95920e2cdfa7ad491a8d8","impliedFormat":99},{"version":"e3667aa9f5245d1a99fb4a2a1ac48daf1429040c29cc0d262e3843f9ae3b9d65","impliedFormat":99},{"version":"08c0f3222b50ec2b534be1a59392660102549129246425d33ec43f35aa051dc6","impliedFormat":99},{"version":"612fb780f312e6bb3c40f3cb2b827ea7455b922198f651c799d844fdd44cf2e9","impliedFormat":99},{"version":"bcd98e8f44bc76e4fcb41e4b1a8bab648161a942653a3d1f261775a891d258de","impliedFormat":99},{"version":"5abaa19aa91bb4f63ea58154ada5d021e33b1f39aa026ca56eb95f13b12c497a","impliedFormat":99},{"version":"356a18b0c50f297fee148f4a2c64b0affd352cbd6f21c7b6bfa569d30622c693","impliedFormat":99},{"version":"5876027679fd5257b92eb55d62efee634358012b9f25c5711ad02b918e52c837","impliedFormat":99},{"version":"f5622423ee5642dcf2b92d71b37967b458e8df3cf90b468675ff9fddaa532a0f","impliedFormat":99},{"version":"70265bc75baf24ec0d61f12517b91ea711732b9c349fceef71a446c4ff4a247a","impliedFormat":99},{"version":"41a4b2454b2d3a13b4fc4ec57d6a0a639127369f87da8f28037943019705d619","impliedFormat":99},{"version":"e9b82ac7186490d18dffaafda695f5d975dfee549096c0bf883387a8b6c3ab5a","impliedFormat":99},{"version":"eed9b5f5a6998abe0b408db4b8847a46eb401c9924ddc5b24b1cede3ebf4ee8c","impliedFormat":99},{"version":"af85fde8986fdad68e96e871ae2d5278adaf2922d9879043b9313b18fae920b1","impliedFormat":99},{"version":"8a1f5d2f7cf4bf851cc9baae82056c3316d3c6d29561df28aff525556095554b","impliedFormat":99},{"version":"d7dfba64b7350cb9501c544fe8ceba1b2455b42029d22b1a4fd02e94a6783525","impliedFormat":1},{"version":"7b0216e822d57877db3fc6e771b3cda58986b429c2b3546e7d23628bf17ccdda","signature":"7b1a4737c7a06365895582efbaaa8b3deb7327f299432f7b7049723ba055056a"},{"version":"5eff8c53ef6e47a15887247db870d5aaff5029bc125c7706f55d4b182be70e51","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"beb521b1cf82b232be75ece872f853a1111bb28d8aba83b03a62f032a546a67e","signature":"93b63cbcbbd23389dc261e87aa92a696608b0ede1cddaba7a725c522ba566f42"},{"version":"ac9e97ea14b27bdd5d12c7398c8b7f46600119450d071f2763962df30b443447","signature":"9e04cbe5f096d06fa663bc956128426a96e7129a089caae9d92f784cafef66cc"},{"version":"4a2547139bdf4736ca79e353b96c3fb08c54201d1d781877c1a6cf2349daab23","signature":"7596522a97f2beba81052a68bc35cf6855073140f872191dcf725b5f0059112b"},{"version":"4819271fa885fd414d5e60eac10bbe17f8c59cc5815f8f43fac4a4bb16dc4c38","signature":"75663620d0609c4decdc6ea0c19da747a85ad3bef012c41c91a2bedfa27423ce"},{"version":"4c4b7d1c6ee35dc775d831d3e96e209711031022829a296aab24e8c9fbad180d","signature":"be4f0c25bcbd8092e7f4c8a8b2c0ced9f555c1dd53acafc86e48c4430c6cd943"},{"version":"78de13fae86a1e31cccb4c61962a172dccf3548f08f800512e1a9b3f2cc67fc6","signature":"9bf3161de2df87ecf14e71df9316bbbcd194e3945408d80c2cccad66075385b0"},{"version":"2ef2418340cb2556fe8a1771c14c01fcac72a6970dcabb3191648e2a94609622","signature":"74978a587f075af8dfbe02da23e9ff3226e8bda586ae4c2fabd446b0f38ff005"},{"version":"bfeb7c41890837848acbd3dbf5d7939b4b8706318637d560c069a40cdc873c12","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"e312ede87ee69b02d22514815e5f5a8a07cf6485173fcdd37840f741674b5809","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"0ee89ff9fc43d0a33c86331cc66d5fcae4175ec81240d4d48d13263df7470771","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f526370b38a3952dc5a6634a56418b6ed5eb6ef4d2c794eb0103fe537e07810e","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"dc8103887511e25d0f660a2ab1eabf6437c0f6827bf154c9d075c6cf8a25ca96","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"1351fae2acc3ce69a615aead940ed3f152ad3ae21e4045562687c695c4f00ec0","signature":"f899edfb18d75b41e4be501a0627dfd98731a0a51d1781740b395a5d96c0855d"},{"version":"5f01d057bbac9f5632c27d61caeeea0b5a32ac5137bc364d62e723ab5692aa8c","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2e1853ab8ee37133893536e4b6df96ecde25fc0ebae9d12cc2538740d64727ba","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2a4886562e374d5e150980fa35170f7271a6991b48abaf68f9d9b653e0c6f360","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"ca1f661f367042bf60d2dfbe7d968a8f5269f63f2d75bfe8f02f8e8bd4cd2001","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f3f5ee76146acc3b8c16f12fe1f4c91cc2ff7d908e3e79b511ad40c90e8a7f9c","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"4c167ad2b3d8495971d78834b7de5fd9f9bfed28c7e5218a687d20940daa80a8","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"421913688ef0cbed2246ac0b1f726e3ea62333f4ae2680bc7fa0dce66a65d57f","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b7f717a6bfa537310086648e5d4c94b953a40799c42cb06ca30e6dd5042bce30","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b80aae4ddad17386d23af2e57c80eb4023349df1de775bc1636f4f4d5243da35","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"c4aeebf2b1b46a87c6343a378991c86c668ec30c8842ec02e95793318fedb0a5","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"8841484f395430c394e96b380118e4a1555b953aa0f3f368a2bdb34cd27b2677","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"e2546064ffe7f13d585e90cc33ac32344390c26641af7ec52b678f03cf3b67bc","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"34b1723e50e00923a742a3a2da6cba4ccacd9f752a5d47f69538d8a017167eae","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"15832f3e3e3502024b1e6539bb5f19c5fc778f51357c793d485c2c2e3feb8191","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"64db123f8b9cd5ca08515ff8313164d7ffba21cfcc2ea0edbdc15d6458e055d9","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"9b4111574776620bc662faf336bf4265360c447349fa3f9e63ea044fc369a11a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"ca7d0b272b14ef02f012e7cdf9a084157e8d4c6127dbb504b4556b6ebdd5a528","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"717b194814015ce9711401b638174f89c93b8f21a612364a8affeaf1bc36dd68","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"d572793d095ab378349061e88a59dea0923aef49b0e02333c0b15df6904dbcb0","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"6bd1377a5a6e8db5fc8c32e63ffce73d05eaa69152f530556c1a22eb647d84c5","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"46293a2b2845ab9b5c3441a3eaf668800d361e03c3e9862f7d732e61fe0fbdcf","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"821c46d3cbd21f1329ffb90aa3b4bfb6394fe4814d3eb4a37716db17ef229b73","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"7f8921eb1f5971d48f52ca717bd3d40db949055fe0b0c9ce05c1b030695153aa","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"82b8b2eb42a0abc39e50dd8c0d073e1d3e395cf349cb31330a71dc5a47422e3d","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"fd111d5d6adc2955510114623699f33528e04ca7524afbde2945124d01270948","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"5d46f2f3e26d48b0035cb50d1471f9c4e237e1962cc79e26df47ab4de49abd8e","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b12cb119e8c252c5fbf5caada506560c15e1d6391d8b2320b7ed386856a63d01","signature":"17c3b358248a966de1c22205f681c835e0c588ecbfb32fd1cd510481ceb25c4b","impliedFormat":99},{"version":"f93315d7a62448443befbe77990490d9cfd06932b1311a01c56d70ab6dd12b2a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"a6ffc92fbc0f167648db8cd9abcfdb77d6c0edd814420c72b12ede4fd8cd7cb4","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"035b3458e8c5f81d0ab218bbec9bd58239c899e5adce7183daed68941f9bf7d3","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"58c3135b3a3e85ec2db5c30d66d59c35d6a054f9281bb1b64bf74f81fb07cc21","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"c71022207ecffdd93335eaa334d49b5f4e1b56bfdbaec431741eb5f41ed0f66a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f0d42590aec58079b64354e21ec7b55145419d0d834bf4bdfadb156189e69a23","signature":"8d339f54a27dc478a44b34270b255c8e2362e2d754eeb735a29580ce1a941d38"},{"version":"5b033de585bf961b3cbd52f1f32e3651aa05ac870c3a65dddce659e6219c86a1","signature":"27c208078b4ff792b7ed107e1e38c3640ec155b1ec2837357b0345a88d0a55cd"},{"version":"8ba13ced58f68fdee135fda4baeb3ccf561260b9704ec6857e41133ab5dbc6b6","signature":"1df6e5922d17077540982513894a34492acb57b26afffa540df0813005f627d8"},{"version":"22efa664b6e4d134773c8c56bc44f036e5bb0d186d88478afd04a5a0dbd4b077","signature":"d4152edc36f5ffa38ede9967609a917a60fb2431e5d28f924b6a8be51ca21d70"},{"version":"fbeef0e5fd7481f4dad55798fe436cd4ad80ca783831c10083c785afc40504e5","signature":"b779181a03f6db3a88eb615029d81e769913625f16a7517bd609b72b8240c914"},{"version":"5e5bf95f14bcc928d627c05b6198997bb9e288bbda629de77bc6d1cffeb80608","signature":"13a994d1bf3b46f39b50e3683ee99320123e035a3676d75b9b39a7fdb84394a7"},{"version":"f74849c171721717e0b17e968588a3924ada9969c5c1c57b183c67d867b1cdf4","signature":"a1f4c95760950f47444f2516a964824bbb7dcf8bdc3aaef3ec3449dc011a734a"},{"version":"88888063a45705833cfcacc3a43179a4583196daab1ca14ef929bc8f3ec94a24","signature":"c519b0a07bbe90c8231c47f5394ed9627427a43689bd36f1b68fe866093c743b"},{"version":"ec7b3626b921955a62862fc02ac2003f0b2efaa8f3b570735c100503e05b602d","signature":"fb014fda83608a28c89ffb998d40410923575136149b3c457cdc3d8ee073c75c"},{"version":"b8612032506f1e43d2ef1dbba330622fd2d1b0f2d9d91c9ee6b29a1bb743e9ef","signature":"d03b433dabb9d865f84627807b2707a864131924aaf97d37bf5f46155f457ba6"},{"version":"2270a8b9a9d7436777e19f7b1faaf4de8aeaedfa986e7f423b361b2bba1d3e0a","signature":"ff13b600261a805ada4bf16372d02ce34a86d1ff7aafcbc9e66d3b8cfd88423e"},{"version":"8265f5c7c3a7273403c53367d751c646aa1c95c57f198f324f9033c726201dd5","signature":"730ee0e6ed0177e399b5f583db579e101db7715c917a06bfefef11bee301a9e6"},{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"f5705d196b442afbdbd971b6e44bad96f4e32afb53cebfa2e5afe3140017bfc6","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},{"version":"77eb0c60ac30b7da409d462da64449ef819339aaf38e15587b84dd5b8f22040f","signature":"0df78f2a4b959a503c31019edc6452ba86f7e272255508119d5ac11a7d9ec71b"},{"version":"300e46eb63f0b333a98ecdf90de67e6adf6aa0bd791dd8710ac03cf78293c27f","signature":"339b6a6006b279b8f12bd877be20037ec23b2da71cc0d63b80ebd4b747fbf856"},{"version":"f53c8e234b40af487ec55d9aa2e768dcc980609a10081f33cade89db21e30aa5","signature":"ff53dc24dd9f26eaca109b151c98025c3e47f72426866ab0bcd101e453dbc9dd"},{"version":"d944cbfdca2e11e9ce24d2413916cd85f1e0b29b085d2d716025b88e150e17da","signature":"0a5a9f14c5cf8c76f560e44248244813b1ebbea85f58b3bfacc20e61aabd1327"},{"version":"0d14b3470b09270093b19111de70964fb88c06641c1dc3020a89ea64064e9418","signature":"99cced08956b46ddaaacfc9e62594334726e43031627301a08ce2b0650d0e0fe"},{"version":"b3753b9221a306f9dd489952deee232c9274490a02670c72f4367eb786f960bd","signature":"3bf5524da51d25be982598eec5529998cb197f60bb3ad40acef50e221e03c605"},{"version":"dca3a26080b5aa921d30dc23d693d28cf567723139a71b0e020b036ce82851de","signature":"0c6f146bf5402327aa93d97c9e263e92bb63b4d87f2af155416cc7d0490a8224"},{"version":"6e56de9ecba8cb849a6bcc17a2cabb21010058d09498e74f36633c2c5030e03c","signature":"8484577cad3452b5fb3e02691d751145198114b555f2d3aefc027d5868d4ceb2"},{"version":"b4b8f490a9690df3e204cbcad422641a85761db8effacb3b9a20859938531bac","signature":"fc3a11ecbcdf46e094cbb65965358353be4b73a70c775b72b8bac3cca74271cc"},{"version":"56208c500dcb5f42be7e18e8cb578f257a1a89b94b3280c506818fed06391805","impliedFormat":1},{"version":"0c94c2e497e1b9bcfda66aea239d5d36cd980d12a6d9d59e66f4be1fa3da5d5a","impliedFormat":1},{"version":"eb9271b3c585ea9dc7b19b906a921bf93f30f22330408ffec6df6a22057f3296","impliedFormat":1},{"version":"aa4a927d0c7239dff845a64e676c71aeed2bbda89a7fb486baab22eb7688ba1d","impliedFormat":1},{"version":"340a990742a00862049b378aaa482b5bb8323d443c799dded51ce711f4f8eb51","impliedFormat":1},{"version":"89eeeebbc612a079c6e7ebe0bde08e06fbc46cfeaebf6157ea3051ed55967b10","impliedFormat":1},{"version":"4c72f66622e266b542fb097f4d1fe88eb858b88b98414a13ef3dd901109e03a1","impliedFormat":1},{"version":"23a933d83f3a8d595b35f3827c5e68239fb4f6eb44e96389269d183fe7ff09ba","impliedFormat":1},{"version":"2acad3ae616a9fb5a8c3d4d7bb5edb11d1d0102372ee939e7fc64359fec4046e","impliedFormat":1},{"version":"c812eabb7d2e13c8e72e216208448f92341a4094dd107cbb0bdb2cb23d1a83e7","impliedFormat":1},{"version":"f734b58ea162765ff4d4a36f671ee06da898921e985a2064510f4925ec1ed062","affectsGlobalScope":true,"impliedFormat":1},{"version":"d39910d4696fac89053561bd0728b83953e80be743b169352701fd3bbe5b1834","impliedFormat":1},{"version":"37f96daaddc2dd96712b2e86f3901f477ac01a5c2539b1bc07fd609d62039ee1","impliedFormat":1},{"version":"9c5c84c449a3d74e417343410ba9f1bd8bfeb32abd16945a1b3d0592ded31bc8","impliedFormat":1},{"version":"a7f09d2aaf994dbfd872eda4f2411d619217b04dbe0916202304e7a3d4b0f5f8","impliedFormat":1},{"version":"86ac756569f83cf0571646c916b546634652e92a775e964304912ecafa81dc42","impliedFormat":99},{"version":"a7f23fecdccf1504dae27c359db676d0a1fbaaeb400b55959078924e4c3a4992","impliedFormat":1},{"version":"bee66a62aa1da254412bb2c3c8c1a0dd12efea0722d35cc6ea7b5fdaa6778fd1","impliedFormat":1},{"version":"05d80364872e31465f8a1eaf2697e4fc418f78aa336f4cea68620a23f1379f6f","impliedFormat":1},{"version":"7345ba3b9eb2182d8cdc4c961b62847c3c9918985179ddefd5ca58a80d8b9e6a","impliedFormat":1},{"version":"81c4a0e6de3d5674ec3a721e04b3eb3244180bda86a22c4185ecac0e3f051cd8","impliedFormat":1},{"version":"39975a01d837394bcac2559639e88ecdc4cfd22433327b46ea6f78eb2c584813","impliedFormat":1},{"version":"7261cabedede09ebfd50e135af40be34f76fb9dbc617e129eaec21b00161ae86","impliedFormat":1},{"version":"ea554794a0d4136c5c6ea8f59ae894c3c0848b17848468a63ed5d3a307e148ae","impliedFormat":1},{"version":"2c378d9368abcd2eba8c29b294d40909845f68557bc0b38117e4f04fc56e5f9c","impliedFormat":1},{"version":"9b048390bcffe88c023a4cd742a720b41d4cd7df83bc9270e6f2339bf38de278","affectsGlobalScope":true,"impliedFormat":1},{"version":"c60b14c297cc569c648ddaea70bc1540903b7f4da416edd46687e88a543515a1","impliedFormat":1},{"version":"acfa00e5599216bcb8c9f3095e5fec4aeddfcc65aabe0eac7e8dbc51e33691c9","impliedFormat":1},{"version":"922d8f0f46dbe9fb80def96f7bcd9d5c1a6c0022d71023afa9eb7b45189d61f2","impliedFormat":1},{"version":"90588fb5ef85f4a8a4234e8062eb97bd3c8114dfb86a0c67f62685969222da8b","impliedFormat":1},{"version":"6ce50ada4bc9d2ad69927dce35cead36da337a618de0a2daaaeeafe38c692597","impliedFormat":1},{"version":"13b8d0a9b0493191f15d11a5452e7c523f811583a983852c1c8539ab2cfdae7c","impliedFormat":1},{"version":"8932771f941e3f8f153a950c65707d0611f30f577256aa59d4b92eda1c3d8f32","impliedFormat":1},{"version":"df6251bd4b5fad52759bfe96e8ab8f2ce625d0b6739b825209b263729a9c321e","impliedFormat":1},{"version":"846068dbe466864be6e2cae9993a4e3ac492a5cb05a36d5ce36e98690fde41f4","impliedFormat":1},{"version":"94c8c60f751015c8f38923e0d1ae32dd4780b572660123fa087b0cf9884a68a8","impliedFormat":1},{"version":"db8747c785df161ef65237bac36a7716168e5ebf18976ab16fd2fff69cf9c6ce","impliedFormat":1},{"version":"3085abdf921a6d225ad037c89eb2ba26a4c3b2c262f842dd3061949d1969b784","impliedFormat":1},{"version":"8e8f7b36675be31c4e9538529c30a552538c42ff866ba59fe70f23ba18479c5a","impliedFormat":1},{"version":"f4f7fbf0e5bf2097ddee2c998cca04b063f6f9cdcb255e728c0e85967119f9e5","impliedFormat":1},{"version":"c5b47653a15ec7c0bde956e77e5ca103ddc180d40eb4b311e4a024ef7c668fb0","impliedFormat":1},{"version":"223709d7c096b4e2bb00390775e43481426c370ac8e270de7e4c36d355fc8bc9","impliedFormat":1},{"version":"0528a80462b04f2f2ad8bee604fe9db235db6a359d1208f370a236e23fc0b1e0","impliedFormat":1},{"version":"17fb3716df78592be07500e9a90bd8c9424dd70c6201226886a8e71b9d2af396","impliedFormat":1},{"version":"82ef7d775e89b200380d8a14dc6af6d985a45868478773d98850ea2449f1be56","impliedFormat":1},{"version":"b86720947f763bbb869c2b183f8e58bca9fa089ed8f9c5a1574b2bea18cfbc02","impliedFormat":1},{"version":"fb7e20b94d23d989fa7c7d20fccebef31c1ef2d3d9ca179cadba6516e4e918ad","impliedFormat":1},{"version":"8326f735a1f0d2b4ad20539cda4e0d2e7c5fc0b534e3c0d503d5ed20a5711009","impliedFormat":1},{"version":"8d720cd4ee809af1d81f4ce88f02168568d5fded574d89875afd8fe7afd9549e","impliedFormat":1},{"version":"df87c2628c5567fd71dc0b765c845b0cbfef61e7c2e56961ac527bfb615ea639","impliedFormat":1},{"version":"659a83f1dd901de4198c9c2aa70e4a46a9bd0c41ce8a42ee26f2dbff5e86b1f3","impliedFormat":1},{"version":"1db5c2491eebd894eb9be03408601cddfe1b08357d021aeb86c3fb6c329a7843","impliedFormat":1},{"version":"224f85b48786de61fb0b018fbea89620ebec6289179daa78ed33c0f83014fc75","impliedFormat":1},{"version":"05fbfcb5c5c247a8b8a1d97dd8557c78ead2fff524f0b6380b4ac9d3e35249fb","impliedFormat":1},{"version":"322f70408b4e1f550ecc411869707764d8b28da3608e4422587630b366daf9de","impliedFormat":1},{"version":"acb93abc527fa52eb2adc5602a7c3c0949861f8e4317a187bb5c3372f872eff4","impliedFormat":1},{"version":"c4ef9e9e0fcb14b52c97ce847fb26a446b7d668d9db98a7de915a22c46f44c37","impliedFormat":1},{"version":"0e447b14e81b5b3e5d83cbea58b734850f78fb883f810e46d3dedba1a5124658","impliedFormat":1},{"version":"045f36d3a830b5ae1b7586492e1a2368d0e4b4209fa656f529fd6f6bb9ac7ced","impliedFormat":1},{"version":"929939785efdef0b6781b7d3a7098238ea3af41be010f18d6627fd061b6c9edf","impliedFormat":1},{"version":"fca68ac3b92725dbf3dac3f9fbc80775b66d2a9c642e75595a4a11a2095b3c9a","impliedFormat":1},{"version":"245d13141d7f9ec6edd36b14844b247e0680950c1c3289774d431cbbd47e714e","impliedFormat":1},{"version":"4326dc453ff5bf36ad778e93b7021cdd9abcfc4efe75a5c04032324f404af558","impliedFormat":1},{"version":"27b47fbd2f2d0d3cd44b8c7231c800f8528949cc56f421093e2b829d6976f173","impliedFormat":1},{"version":"0795a213434963328e8b60e65a9d03a88efc138ae171bbcca39d9000c040e7a4","impliedFormat":1},{"version":"fc745bebefc96e2a518a2d559af6850626cada22a75f794fd40a17aae11e2d54","impliedFormat":1},{"version":"2b0fe9ba00d0d593fb475d4204214a0f604ad8a56f22a5f05c378b52205ef36b","impliedFormat":1},{"version":"3d94a259051acf8acd2108cee57ad58fee7f7b278de76a7a5746f0656eecbff6","impliedFormat":1},{"version":"46097d076be332463ea64865c41d232865614cf358a11af75095dd9cef2871cc","impliedFormat":1},{"version":"6e18a70a7c64e6fe578a8f3ecc1dd562cd0bf6843bbf8e65fde37cf63b9a8ea8","impliedFormat":1},{"version":"3f3526aea8d29f0c53f8fb99201c770c87c357b5e87349aca8494bfd0c145c26","impliedFormat":1},{"version":"6ee92d844e5a1c0eb562d110676a3a17f00d2cd2ea2aaaff0a98d7881b9a4041","impliedFormat":1},{"version":"b9dc36d1f7c5c2350feafb55c090127104e59b7d2a20729b286dab00d70e283d","impliedFormat":1},{"version":"45d3f1d53fa99783a5e3c29debb065d6060d0db650a6a1055308a8619bd6b263","impliedFormat":1},{"version":"a14febaf38fd75a88620a0808732cf9841afc403da2dc3de7a6fc9a49d36bdbc","impliedFormat":1},{"version":"6052522a593f094cfee0e99c76312a229cf2d49ac2e75095af83813ec9f4b109","impliedFormat":1},{"version":"a0ceb6ce93981581494bae078b971b17e36b67502a36a056966940377517091d","impliedFormat":1},{"version":"a63ce903dd08c662702e33700a3d28ca66ed21ac0591e1dbf4a0b309ae80e690","impliedFormat":1},{"version":"2b63d2725550866e0f2b56b2394ce001ebf1145cb4b04dc9daa29d73867b878c","impliedFormat":1},{"version":"e885933b92f26fa3204403999eddc61651cd3109faf8bffa4f6b6e558b0ab2fa","impliedFormat":1},{"version":"bd834465d4395ac3d8d55e94bf2a39c1f5e9be719c99340957b3b6a3a85ec66a","impliedFormat":1},{"version":"fca1059bad0f439021325957b33c933bca31475e4a3a36dda02140f47ffaf8ed","impliedFormat":1},{"version":"6e2d2b63c278fd1c8dd54da2328622c964f50afa62978ed1a73ccd85e99a4fc7","impliedFormat":1},{"version":"e151e41c82004cf09b7ea863f591348c9035e0f7a69d4189cbac89cc9611b89d","impliedFormat":1},{"version":"0778cfe0d671f153a9d30655b81d5721dc7af6ebe4b654c57417b7cba3649b1c","impliedFormat":1},{"version":"b83ffe71adbac91c5596133251e5ec0c9e6664017ee5b776841effe93de8f466","impliedFormat":1},{"version":"61ecf051972c69e7c992bab9cf74c511ecba51b273c4e1590574d97a542bd4ea","impliedFormat":1},{"version":"068f5afbae92a20a5fcd9cfce76f7b90de2c59a952396b5da225b61f95a1d60a","impliedFormat":1},{"version":"bdf5e07a22e661de2c7115e8364b98ef399c24c9fe62035dc1ac945a9dd3372a","impliedFormat":1},{"version":"4e024e2530feda4719448af6bdd0c0c7cfa28d1a4887900f4886bec70cd48fea","impliedFormat":1},{"version":"99c88ea4f93e883d10c04961dbf37c403c4f3c8444948b86effec0bf52176d0e","impliedFormat":1},{"version":"e88f3729fcc3d38d2a1b3cdcbd773d13d72ea3bdf4d0c0c784818e3bfbe7998d","impliedFormat":1},{"version":"f25b1264b694a647593b0a9a044a267098aaf249d646981a7f0503b8bb185352","impliedFormat":1},{"version":"964d0862660f8e46675c83793f42ab2af336f3d6106dee966a4053d5dc433063","impliedFormat":1},{"version":"292ad4203c181f33beb9eb8fe7c6aaae29f62163793278a7ffc2fcc0d0dbed19","impliedFormat":1},{"version":"aa8e5ac3f73eede931d5da74ef1797c174b00854ac701ead5c4a7d6ce4a49029","impliedFormat":1},{"version":"f1a4ca3688d951daa2d7740da5a0827fa34d4a7709eed7b8225215986ee87108","impliedFormat":1},{"version":"08e159b5ef9d14bdd329457c5cbe181e84f13c4ff2546a24b9eb9129b0c71c46","impliedFormat":1},{"version":"f8453a3fe0fe49ab718357120bec2b8205e15eb91ff62eada60a4780458fa91e","impliedFormat":1},{"version":"06f186bb9a6408ef8563dbf17d53cbe23e68422518b49b96afac732844ddbaa1","impliedFormat":1},{"version":"525f9c06245b5b43b1237cfd757396fd7fd8090e5d6a4ded758c7ce17a04bf42","impliedFormat":1},{"version":"04bc74b8fa987f140989e9f4d6dc37f04a307417af3e0a3767baa1eef4964e10","impliedFormat":1},{"version":"6a9d3aa58228faa62ec3d9e305f472a24441f22a8d028234577beb592ec295b2","impliedFormat":1},{"version":"683e2d454f64394931d233740b762dabc379e3ce5c4c4ad4747cdbd6d5fd8e8d","impliedFormat":1},{"version":"18594ddc7900f3e477645819bce4d824989ad296e3d70bdcdce13cabc5d97335","impliedFormat":1},{"version":"9376cce4d849f1d6ad2cb0048807c77cfeb78cee6e29b61dcfe74c7ab2980e18","impliedFormat":1},{"version":"2698935791615907eb632186119dfc307363d6a163f26017084009e44ea261f2","impliedFormat":1},{"version":"4edfc4848068bf58016856dfeb27341c15679884575e1a501e2389a1fea5c579","impliedFormat":1},{"version":"0c3d7a094ef401b3c36c8e3d88382a7e7a8b1e4f702769eba861d03db559876b","impliedFormat":1},{"version":"d3c3280f081f28e846239d27c2f77a41417e6a19f39267d20a282fd07ef36b96","impliedFormat":1},{"version":"7e3a4800683a39375bc99f0d53b21328b0a0377ab7cbb732c564ca7ca04d9b37","impliedFormat":1},{"version":"c777b498a93261d6caa5dbd1187090b79f0263a03526c64ea4f844a679e8299e","impliedFormat":1},{"version":"b4677e9d8802a82455a0f03a211b85f5d4b04cfbc89fc9aa691695b8e70df326","impliedFormat":1},{"version":"7cb0d946957daea11f78a31b85de435e00bcd8964eba66d3e8056ba9d14b9c55","impliedFormat":1},{"version":"b3e441cdb9d9e55e6e120052fe8bf2a8b5e5a46287f21d5bc39561594574e1a9","impliedFormat":1},{"version":"0870e8eb0527c044e844a1d83127f020aa7f79048218a62b2875e818355f8cb2","impliedFormat":1},{"version":"6b7446f89f9e5d47835117416e6d7656bac2bf700513d330254ae979260ce99f","impliedFormat":1},{"version":"9750752db342b88df1b860958a20fac9fd6a507f67c5cfb6bd5cfa8759338b1e","impliedFormat":1},{"version":"946de511c5e04659d9dfaf5ef83770122846d26d3ffe30e636d3339482bbf35a","impliedFormat":1},{"version":"fbcc201a8fc377a92714567491e3f81e204750b612d51a1720af452f1a254760","impliedFormat":1},{"version":"6dd704b0ba0131eb9e707aeedc39be6a224b4669544e518217a75eb7f5dd65c2","impliedFormat":1},{"version":"6effa89f483e5c83c0e0063df5f1d8b006d9d0f1de7eed2233886642424dc8fb","impliedFormat":1},{"version":"84a8c844f9562da8994c07b44dd2777178a147e06020c62a7f6e349e695e7149","impliedFormat":1},{"version":"d43130c35762a80da2299f8b59a4321b6e64acfb0b11a36183379b4c7b83314b","impliedFormat":1},{"version":"6bf44b890824799af8e20c0387ffa987e890fac5c5954a3a7352351eefe55d5d","impliedFormat":1},{"version":"892b19153694b7a3c9a69bcedb54e1c8ad3b9fa370076db4d3522838afd2cd60","impliedFormat":1},{"version":"5461fca70947a4d8fa272d3dda4c729317cec825141313352adf33bc94de142a","impliedFormat":1},{"version":"f83afa274e0f11860c6609198ecca220f5df60690923b990ca06cae21771016e","impliedFormat":1},{"version":"af31f37264ea5d5349eec50786ceca75c572ed3be91bdd7cb428fdd8cd14b17c","impliedFormat":1},{"version":"85e4673ec8507aef18afd4a9acfae0294bdfaac29458ede0b8b56f5a63738486","impliedFormat":1},{"version":"40683566071340b03c74d0a4ffa84d49fedb181a691ce04c97e11b231a7deee4","impliedFormat":1},{"version":"81c8ab81daa2286241ad27468d6fc7ad3ecc62da04b18b77ce9b9b437f6b0863","impliedFormat":1},{"version":"f158721f7427976b5510660c8e53389d5033c915496c028558c66caaf3d1db1c","impliedFormat":1},{"version":"8e56db8febfe127a9142435940c9a5a1ad17ddb2b2a6d8e9e8984785a76db1fd","impliedFormat":1},{"version":"6113c2f172a875db117357f0aa35aa7c1b6316516e813977ef98dc3b4b8baf2a","impliedFormat":1},{"version":"f25c9802b1316afbf667dd8fa6db4ed23aa5e7acc076a1054ca45d7bc9c8e811","impliedFormat":1},{"version":"e99285f74c22ad823c0b9fac55316b84144e15eb91830034badd9eb0fafe71bf","impliedFormat":1},{"version":"88bbd40c3aa0fe7d7dae94e4abeb801a383b58f3990d00f79a0177de20ae4c91","signature":"ec9a40758ca7f31281c07e318f0c065dc02032a8ecc102f0de70d1286eb5ffe2"},{"version":"d6b1569f5aeaa6e763bba5a188958100bd22a06677a1b55b4962107c7e324a0e","signature":"458b890fb07a867fd5e9792a602501742ea05319f77c0bf4311184e1e5408682"},{"version":"eb52c97a1aceb729ada6aa0cd8d2ff60c471fc367294e460148bc1fae01eddac","signature":"12e0e1bddfaef186c90ba76edb1de07e31fe228a8b238c5cac38e335cedd308f"},{"version":"c075782d15339ec51749c1b0b15fb6488decd266603edbfd9c29ef07da559e10","signature":"b96102d8ef5e0fdc0cdeb221b598e16eba123e88de03d9bb93492f5ab45cfde6"},{"version":"a397b2363fc3bdbc08f30a9fd1b01cfd714d8dbd28b91bd94ad77d1fd57b77dc","signature":"0597c79bf0c62a926d05ce64fd1f13bb81dc8284002fc4713da65cc871669947"},{"version":"213a83bf967516b551a7b9e9a9b38a2923f135ce1e785ed7cbd4de8471f2e5cd","signature":"2792b28d13f79001ac02499432d0a14241f49fd7dc00053d725256f119918ec4"},{"version":"4ddd72fa5c7491ca175087b8c7cfba2710f560961c4ab790519b9203c6cdf01c","signature":"b3ee5184dbf154ca01ff12e4703e5dc467ad7c79d8b16c98b8361118de54cea4"},{"version":"432bfc0208644d1507cbdac496cd1e875a701293ecf0d4458a8a53dd19af39a9","signature":"7a4fe07bffc8b6ec1785aec2b011f454fc93828d90b9269ccdda995af85bf073"},{"version":"afe7006d37b92707b28ec7e0db00b3d267e7d776c36998867afd5171772e7e4b","signature":"1a6115819fa1e86a8fdfdef41f15eb65ba315a1ab6079a7db3f018bf72f4c0c2"},{"version":"e96401cdc92c18d21624a8f82ea7c8aa6df6aaa54d66d686cf88d500378f9739","signature":"043305f7cc5424c8058fcf13c519a5baee2861091efda10e73b38c4c119cab0f"},{"version":"7642d023b24a165bd92b4ecbf2b96665a224f7d7f1fa93b9ae308ac9d50dc101","signature":"73a68f6952a1d7ef44f439032cc7328d6cd34acdc57cf8045f6510d69ecbc08a"},{"version":"f9ba280ed9e3f159e8813fcda71b5255dd1c54735890a1aba7e1a383413bdc26","signature":"c01db3fe3a0f722df012fd4b2b4770e630514dac527c5c1a17f61cc18290ce56"},{"version":"b2f52dc18fc56d792e62194014006dfef3f21e8ccee687e620e010222609411a","signature":"4700c4aaa2f5711d21a8cd9a22eef223fe7b80bd96a12d3467cb6f84c81a3f25"},{"version":"2fed8019f865cb0200606eea95cc89c41db2bfb85183a44dff626ac5a0502000","signature":"6f3f957c96636ca2de4458705c17b3a0de56bd955d5c1d07823a1d1e7596a87c"},{"version":"4613ca971bf8e2a367c95f92ad58e1bdf11aebb1144059e81da884ac2df1656c","signature":"f07c363fb0ea6003e19b1868846ad4a20bb9ff1114ff67d1e3d022220c7acd38"},{"version":"633c5ae5eb8d08a03e9577b3bee22bb46be7bc4e481d9166f83541fa6196e63d","signature":"473acc9d06c667b825d3ea4a0365a8de60d4eac8082bcb2ddc13a71f39d849f5"},{"version":"037ab3e7f898bb6a441320748b7a2468682370aa6c5abeae6d6f457a57958334","signature":"3578485119428d27423fc47567cab1594ba680131f8aa50bbb60ff89b400a87c"},{"version":"2908e14681d109d8ecb2a82da30809b4e3d0fac40a1a1c94bfb90f766f47abad","signature":"da7cee797fe306639de8046a491e353d0d9930f3679aab767fab6d6315e1d8e3"},{"version":"5ba09493d0df0e34a69f0b7a9c78ca5ddef2fadc1084825f0422f42acb021e5b","signature":"f774a7e8875649db68f5952801f001f3c316560ede472e5663af7a8c9c18f938"},{"version":"a0f771695d600565372688bb572008d3b71dc39891be1ed07968676dff1eae45","signature":"41d1155560bbe4fe6681240251fccfe72f28c593ae0b1991740b4b9b9f4c4594"},{"version":"a1c0ee2a4b5a53e165844565de3a22b1a327414034e91d708864e166e8edd5c4","signature":"9bd36072e3c548bea745c4d4fd7da6fe5ed01ddee223239b39a25e4b51035261"},{"version":"05790534533bfb89097e921ab621c106b670aa942def56efcacca9b9f326ccff","signature":"5eb22f1450a20efb3e3060d8881e74d6de7d2ebb2955ecb6a4a3c8dfbf46c10f"},{"version":"37c5a077bc5d6cc1809af67348de0208ed5718d5390cb44df25d8edf9268f458","signature":"715e76a1478244b19dbf0b41c492c69f947c68b13679941b20d6b4a07ca34451"},{"version":"a11bd31045c49b20f275a5cf9e67f6926242d525fcd1fcfa92cea5b237bd0007","signature":"5f4697c448f9a8526c9df3da777b56c0aa72a951e7161c497c35e033b76a6f2c"},{"version":"74ff76c709f5e3ceb17076240228814eba7a0ff132806c3517536be0839e2dc3","signature":"603bed59050fefb5195265c6ac968e11857bda170f505abae14a05153c94b5dc"},{"version":"1d298f30d798a5b91f1f2d333ec584d4b6b75af1ac6ebfa8d1f752d78259fa66","signature":"00fedf01af9dc24abbf26df685583807591f79592e00cc9922a36600fe9167b7"},{"version":"b0961489210ae8d09bc7e484ef156225b4b96a320d5c6b91772117455753407c","signature":"1ae2f05788b1e03822b981f36a7dc7c207555d6a40b98c11225ffc4e93e14492"},{"version":"61a3711a74305ee330770f87af07d2ac9c6426536e65f59891141dc5bc890b6a","signature":"5f4b9f0ce89a67f4f046ceb82d0b89d7b3b1fa37d106a82359dba971d3a861aa"},{"version":"a2c0dbec0f266a602118e11ed4e9ae441b3ccabcc1b0d629dbc6e0595a94000a","signature":"c80b086381a37721ff37990db6b451b69da774f3a1725f7bcd87e3eae2d1dea3"},{"version":"99c7dfdc58e36886b2d8efcefe74e1deabf943c8a41ae094009354c91cca1048","signature":"14015613b6b5d535af589c95b5d2b0533b6db9e709fa964c5324b48ec6ffc1c8"},{"version":"cc0db34c3fa72ad32b36db06b2921b228ddc3921cf91076ce762c550ff28a265","impliedFormat":1},{"version":"39cec3d65003f318688e3a4d0afe09727ca2d588d4c157a6dcbfeee57a63f5b0","impliedFormat":1},{"version":"6bd806123fc5a3786f2066e08d6fb99f1d5f7bb01576b8c97baff19cbea2c356","signature":"5acc6e5a6a4c12dc7df15fa03233f2b08532fd64b065952c6bffbf0ac7d81613"},{"version":"5f3b5b37819db592bda1665e5b0b2b28e13a0acf2db94eaccec4e34f862b8750","signature":"057165dec26156c33bb0cb3d310ee667e77ee7b01f67838585999f4717d9c8b5"},{"version":"ca83a1279bd3ffb830a94cec8ae174cd78b8ffc5f58ba5128e80f4158623f53a","signature":"3ea6802273aae6eb3e95ad5d3d352bb963f22992f6923ee3ccf523d2d9da372c"},{"version":"2d25dc2c380ed42a8c79bd9e51d144e31929e382496f547bd5743ad80a45e3e3","signature":"7623617f3636b848a563dca43cc1338305e2bed0f88e78fa17708d73c414ab39"},{"version":"d788b97e4d0fafdfae1de75cf7a5bc13f4611aa93402d4cd20967880bc54d1b8","signature":"3d7abe3fb35f56f12c72a04507b9a76d2d5e395a556de74daa320d670ca689e2"},{"version":"08e64ac1fae5aea1009c040e6d08647f8a642523e0177c52c6581edd69f412d9","signature":"e7e136f89e9e90468dd1a1789d7f8d6f5371d7115fa60ac54dcbcdd16bd4e212"},{"version":"3fb176d1fca38c42cf87c5685e177789457ca463a0fcad5ecee0917f4a6eef67","signature":"0078116c0e25922860911af3973f73124e7b73d1583b50bdd0254590b081dc5d"},{"version":"2d6771f971781cf86ebe59c6f206c0a7fa237d361d32c62c6778f53034e4b4e1","signature":"3ba3ffa82fa93c65873e7bbc879d6958ee9e40714b2024c2076ce803a9b28406"},{"version":"42fdc31f8ac3965c84b5d7acbf86e982c43f7c3c6c07e08e5484335ca1c9c5d1","signature":"9da6f875aebceb82f2e7d2ba0bc974c1824b0ba0f054e3a6955d07af03e7fa0f"},{"version":"7cb9cfc82c15eec3a953194c87e3f585bc429b5d2173553587fc46244fd7dec5","signature":"26094f320ab424d4758e8336b531f67cd1a11cf37794797b65ae57dc0695922c"},{"version":"623ee4f87660cf41ef7befe5df8ef7698f8518bd5479bf474cb6f60d0d2b94c9","signature":"f0b39f93b51bcc9e2bb0389147acb24737f891ed6cee91e68f7aa68e3f15e565"},{"version":"080596978b4428bd4d5a945e81ead23cb27bfe55892ab757e4885d82f5561e20","signature":"72b44aff47c18d445d5e30bb96d19cfebf9e83a198261cb7c17ac97866a2a0c7"},{"version":"bbeb2f7ac5cde5ae87370ec5e9ba75a560f7cc4d64ba9de61938f234173e7074","signature":"5214d218cbac4fb384c98ad4d126ba9d9dbafe5c93cf0e4ab12646c066c6e1a3"},{"version":"ff029b98f175c72bc1f57ad1808a5862436b52d8957a15ad08159e223a96d250","signature":"eced1bebbb48e0e464e620e5ed6e87668e4197e8a7f7c9d6b27ab29713aac1f9"},{"version":"b62b159e14eb3ad46e830c94509eccbe1e3757b473905cbfce3905665c50cf9c","signature":"ff2aba4f828224889112337f01c22428109587066c3d410c83ce048e94b302e2"},{"version":"673cfdfcfc12d7568bead946f93e06718eb9a518ca25b041af0145b0b590891b","signature":"4e73a942c8cc891412347e7a919e7fd836f8def74155c986a4a2d68de490159f"},{"version":"f4e61e53002aa59dd7a516f83e6230228b486d69733345001efbcc6a0ddb9d67","signature":"b9f1bf3713fc43fd9e929b746540e6d606807cc121fe59d4454efdf3b009c18a"},{"version":"5c3899347135fd5940962d9f68926eb38255898f138c7ca6e78e08fed99ef71a","signature":"fff78d55a5efd4bc32447cbf63580f39272c762b7cf884017db7cf5a5dadef9b"},{"version":"b1538a92b9bae8d230267210c5db38c2eb6bdb352128a3ce3aa8c6acf9fc9622","impliedFormat":1},{"version":"6fc1a4f64372593767a9b7b774e9b3b92bf04e8785c3f9ea98973aa9f4bbe490","impliedFormat":1},{"version":"ff09b6fbdcf74d8af4e131b8866925c5e18d225540b9b19ce9485ca93e574d84","impliedFormat":1},{"version":"d5895252efa27a50f134a9b580aa61f7def5ab73d0a8071f9b5bf9a317c01c2d","impliedFormat":1},{"version":"1f366bde16e0513fa7b64f87f86689c4d36efd85afce7eb24753e9c99b91c319","impliedFormat":1},{"version":"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","impliedFormat":1},{"version":"89e326922cadcc2331d7e851011cf9f0456a681aaf3c95b48b81f8d80e8cdfba","impliedFormat":1},{"version":"751764bb94219b4ce8f5475dc35d3de2e432fea01a0c9610cd7f69ad05e398c6","impliedFormat":1},{"version":"5d08a179b846f5ee674624b349ebebe2121c455e3a265dc93da4e8d9e89722b4","impliedFormat":1},{"version":"11a3a97b6f4ebeb1464f05e932538532efaf939094a2df2bb8ba5c7013b2c299","impliedFormat":1},{"version":"1f4ae755492a669b317903a6b1664cb7af3fe0c3d1eec6447f4e95a80616d15a","impliedFormat":1},{"version":"7fa8d75d229eeaee235a801758d9c694e94405013fe77d5d1dd8e3201fc414f1","impliedFormat":1},{"version":"0b301e46295e7dee8bcead624b4a0f94ab8ba1cb3f572b726977322293be2196","impliedFormat":1}],"root":[488,489,[495,500],[502,524],[528,535],[539,545],[547,568],[579,600],[652,654],[700,740],[742,758],[762,770],[908,937],[940,957]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":9},"referencedMap":[[488,1],[489,2],[939,3],[230,4],[604,5],[608,6],[613,7],[617,8],[614,8],[615,9],[616,10],[607,9],[622,11],[605,5],[612,12],[623,5],[609,8],[624,11],[610,8],[626,13],[625,8],[627,14],[621,15],[629,16],[631,17],[632,18],[633,5],[634,19],[619,20],[611,8],[606,5],[636,21],[620,9],[637,9],[638,19],[640,9],[641,5],[642,9],[643,21],[644,22],[646,23],[645,8],[648,24],[647,8],[649,14],[630,8],[618,4],[786,25],[785,26],[782,4],[501,27],[958,4],[959,4],[960,4],[961,28],[795,4],[772,29],[796,30],[771,4],[962,4],[964,31],[966,32],[965,4],[491,4],[656,33],[666,33],[963,4],[118,34],[119,34],[120,35],[74,36],[121,37],[122,38],[123,39],[69,4],[72,40],[70,4],[71,4],[124,41],[125,42],[126,43],[127,44],[128,45],[129,46],[130,46],[131,47],[132,48],[133,49],[134,50],[75,4],[73,4],[135,51],[136,52],[137,53],[169,54],[138,55],[139,56],[140,57],[141,58],[142,59],[143,60],[144,61],[145,62],[146,63],[147,64],[148,64],[149,65],[150,4],[151,66],[153,67],[152,68],[154,69],[155,70],[156,71],[157,72],[158,73],[159,74],[160,75],[161,76],[162,77],[163,78],[164,79],[165,80],[166,81],[76,4],[77,4],[78,4],[117,82],[167,83],[168,84],[173,85],[390,5],[174,86],[172,87],[392,88],[391,89],[170,90],[388,4],[171,91],[60,4],[62,92],[387,5],[247,5],[967,93],[968,4],[655,4],[969,4],[970,4],[79,4],[573,94],[571,4],[572,95],[537,96],[538,97],[603,98],[602,99],[574,4],[601,4],[570,100],[569,4],[938,4],[61,4],[527,101],[526,102],[525,4],[577,103],[578,104],[576,105],[901,4],[490,4],[826,4],[699,5],[694,106],[668,107],[669,108],[670,108],[671,108],[672,108],[673,108],[674,108],[675,108],[676,108],[677,108],[678,108],[692,109],[679,108],[680,108],[681,108],[682,108],[683,108],[684,108],[685,108],[686,108],[688,108],[689,108],[687,108],[690,108],[691,108],[693,108],[667,110],[437,111],[442,112],[432,113],[194,114],[234,115],[416,116],[229,117],[211,4],[386,4],[192,4],[405,118],[260,119],[193,4],[314,120],[237,121],[238,122],[385,123],[402,124],[296,125],[410,126],[411,127],[409,128],[408,4],[406,129],[236,130],[195,131],[339,4],[340,132],[266,133],[196,134],[267,133],[262,133],[183,133],[232,135],[231,4],[415,136],[427,4],[219,4],[361,137],[362,138],[356,5],[464,4],[364,4],[365,139],[357,140],[469,141],[468,142],[463,4],[281,4],[401,143],[400,4],[462,144],[358,5],[290,145],[286,146],[291,147],[289,4],[288,148],[287,4],[465,4],[461,4],[467,149],[466,4],[285,146],[456,150],[459,151],[275,152],[274,153],[273,154],[472,5],[272,155],[254,4],[475,4],[760,156],[759,4],[478,4],[477,5],[479,157],[176,4],[412,158],[413,159],[414,160],[189,4],[222,4],[188,161],[175,4],[377,5],[181,162],[376,163],[375,164],[366,4],[367,4],[374,4],[369,4],[372,165],[368,4],[370,166],[373,167],[371,166],[191,4],[186,4],[187,133],[242,4],[248,168],[249,169],[246,170],[244,171],[245,172],[240,4],[383,139],[269,139],[436,173],[443,174],[447,175],[419,176],[418,4],[257,4],[480,177],[431,178],[359,179],[360,180],[354,181],[345,4],[382,182],[421,5],[346,183],[384,184],[379,185],[378,4],[380,4],[351,4],[338,186],[420,187],[423,188],[348,189],[352,190],[343,191],[397,192],[430,193],[300,194],[315,195],[184,196],[429,197],[180,198],[250,199],[241,4],[251,200],[327,201],[239,4],[326,202],[68,4],[320,203],[221,4],[341,204],[316,4],[185,4],[215,4],[324,205],[190,4],[252,206],[350,207],[417,208],[349,4],[323,4],[243,4],[329,209],[330,210],[407,4],[332,211],[334,212],[333,213],[224,4],[322,196],[336,214],[299,215],[321,216],[328,217],[199,4],[203,4],[202,4],[201,4],[206,4],[200,4],[209,4],[208,4],[205,4],[204,4],[207,4],[210,218],[198,4],[308,219],[307,4],[312,220],[309,221],[311,222],[313,220],[310,221],[220,223],[270,224],[426,225],[481,4],[451,226],[453,227],[347,228],[452,229],[424,187],[363,187],[197,4],[301,230],[216,231],[217,232],[218,233],[214,234],[396,234],[264,234],[302,235],[265,235],[213,236],[212,4],[306,237],[305,238],[304,239],[303,240],[425,241],[395,242],[394,243],[355,244],[389,245],[393,246],[404,247],[403,248],[399,249],[298,250],[295,251],[297,252],[294,253],[335,254],[325,4],[441,4],[337,255],[398,4],[253,256],[344,158],[342,257],[255,258],[258,259],[476,4],[256,260],[259,260],[439,4],[438,4],[440,4],[474,4],[261,261],[422,4],[292,262],[284,5],[235,4],[179,263],[268,4],[445,5],[178,4],[455,264],[283,5],[449,139],[282,265],[434,266],[280,264],[182,4],[457,267],[278,5],[279,5],[271,4],[177,4],[277,268],[276,269],[223,270],[353,63],[263,63],[331,4],[318,271],[317,4],[381,146],[293,5],[428,161],[435,272],[63,5],[66,273],[67,274],[64,5],[65,4],[233,275],[228,276],[227,4],[226,277],[225,4],[433,278],[444,279],[446,280],[448,281],[761,282],[450,283],[454,284],[487,285],[458,285],[486,286],[460,287],[470,288],[471,289],[473,290],[482,291],[485,161],[484,4],[483,27],[575,292],[650,293],[628,8],[635,9],[639,8],[698,294],[697,295],[536,296],[812,4],[810,297],[814,298],[881,299],[876,300],[779,301],[847,302],[840,303],[897,304],[777,305],[846,306],[835,307],[880,308],[877,309],[829,310],[839,311],[882,312],[883,312],[884,313],[892,314],[886,314],[894,314],[898,314],[885,314],[887,314],[890,314],[893,314],[889,315],[891,314],[895,316],[888,317],[789,318],[861,5],[858,319],[862,5],[800,314],[790,314],[853,320],[778,321],[799,322],[803,323],[860,314],[775,5],[859,324],[857,5],[856,314],[791,5],[903,325],[871,317],[851,326],[907,327],[869,4],[867,4],[872,328],[870,329],[866,330],[868,331],[873,332],[875,333],[865,5],[798,334],[774,314],[864,314],[813,335],[863,5],[838,334],[896,314],[831,336],[787,337],[792,338],[841,339],[843,336],[822,340],[825,336],[804,341],[824,342],[833,343],[834,344],[830,345],[844,346],[832,347],[809,348],[852,349],[848,350],[849,351],[845,352],[823,353],[811,354],[816,355],[793,356],[820,357],[821,358],[817,359],[794,360],[805,361],[842,344],[788,362],[850,4],[815,363],[808,364],[836,4],[905,365],[906,366],[878,4],[904,367],[899,4],[827,4],[801,4],[874,368],[828,4],[780,367],[902,369],[807,370],[837,371],[806,372],[879,373],[818,4],[854,4],[855,374],[802,4],[819,4],[900,4],[776,5],[784,375],[781,4],[696,376],[695,377],[783,4],[492,378],[319,379],[493,4],[651,4],[546,4],[663,380],[662,4],[494,381],[58,4],[59,4],[10,4],[11,4],[13,4],[12,4],[2,4],[14,4],[15,4],[16,4],[17,4],[18,4],[19,4],[20,4],[21,4],[3,4],[22,4],[23,4],[4,4],[24,4],[28,4],[25,4],[26,4],[27,4],[29,4],[30,4],[31,4],[5,4],[32,4],[33,4],[34,4],[35,4],[6,4],[39,4],[36,4],[37,4],[38,4],[40,4],[7,4],[41,4],[46,4],[47,4],[42,4],[43,4],[44,4],[45,4],[8,4],[51,4],[48,4],[49,4],[50,4],[52,4],[9,4],[53,4],[54,4],[55,4],[57,4],[56,4],[1,4],[95,382],[105,383],[94,382],[115,384],[86,385],[85,386],[114,27],[108,387],[113,388],[88,389],[102,390],[87,391],[111,392],[83,393],[82,27],[112,394],[84,395],[89,396],[90,4],[93,396],[80,4],[116,397],[106,398],[97,399],[98,400],[100,401],[96,402],[99,403],[109,27],[91,404],[92,405],[101,406],[81,407],[104,398],[103,396],[107,4],[110,408],[665,409],[661,4],[664,410],[658,411],[657,33],[660,412],[659,413],[773,414],[797,415],[496,416],[741,26],[517,417],[518,418],[520,419],[532,420],[531,421],[533,422],[534,423],[540,424],[542,425],[541,425],[550,426],[549,426],[553,427],[552,428],[556,429],[558,430],[551,431],[562,432],[563,433],[565,434],[561,435],[566,423],[560,436],[568,437],[567,438],[923,439],[768,440],[925,441],[915,442],[927,443],[936,444],[934,445],[937,446],[946,447],[949,448],[595,449],[590,450],[583,451],[584,452],[588,453],[594,454],[585,453],[592,455],[593,456],[581,457],[586,458],[589,459],[591,460],[587,461],[596,462],[579,463],[580,26],[597,464],[950,465],[910,466],[770,467],[951,468],[912,469],[769,470],[913,471],[952,472],[911,473],[953,474],[908,475],[917,476],[922,477],[954,478],[945,479],[941,480],[942,481],[598,482],[940,483],[944,484],[943,485],[765,486],[764,487],[767,488],[924,489],[930,490],[933,491],[928,492],[931,493],[701,494],[700,495],[935,496],[766,497],[918,498],[653,498],[916,499],[932,500],[955,501],[926,499],[929,502],[919,502],[909,502],[763,501],[956,502],[914,473],[957,502],[920,499],[921,498],[654,499],[762,502],[948,503],[947,504],[709,505],[710,506],[711,507],[712,508],[713,509],[715,510],[716,511],[717,512],[718,513],[719,514],[720,515],[721,516],[722,517],[723,518],[724,519],[725,520],[726,521],[727,522],[728,523],[729,524],[730,525],[731,526],[732,527],[733,528],[734,529],[735,530],[736,531],[737,532],[738,533],[739,534],[740,535],[742,536],[743,537],[744,538],[745,539],[746,540],[714,541],[516,542],[502,26],[498,543],[519,544],[500,545],[513,546],[582,547],[547,548],[507,549],[702,550],[703,551],[530,552],[652,553],[705,554],[704,26],[503,555],[504,556],[706,550],[528,557],[529,558],[539,559],[497,26],[514,560],[707,561],[524,562],[522,464],[523,457],[515,563],[509,564],[543,565],[544,26],[548,566],[545,567],[499,568],[554,569],[555,570],[506,550],[512,571],[559,550],[708,572],[564,573],[511,550],[505,26],[508,26],[521,26],[557,574],[510,575],[599,576],[747,577],[748,578],[749,579],[750,580],[751,139],[600,581],[752,582],[753,583],[754,584],[755,582],[756,139],[757,139],[758,580],[535,425],[495,585]],"affectedFilesPendingEmit":[489,496,741,517,518,520,532,531,533,534,540,542,541,550,549,553,552,556,558,551,562,563,565,561,566,560,568,567,923,768,925,915,927,936,934,937,946,949,595,590,583,584,588,594,585,592,593,581,586,589,591,587,596,579,580,597,950,910,770,951,912,769,913,952,911,953,908,917,922,954,945,941,942,598,940,944,943,765,764,767,924,930,933,928,931,701,700,935,766,918,653,916,932,955,926,929,919,909,763,956,914,957,920,921,654,762,948,947,709,710,711,712,713,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,742,743,744,745,746,714,516,502,498,519,500,513,582,547,507,702,703,530,652,705,704,503,504,706,528,529,539,497,514,707,524,522,523,515,509,543,544,548,545,499,554,555,506,512,559,708,564,511,505,508,521,557,510,599,747,748,749,750,751,600,752,753,754,755,756,757,758,535,495],"version":"5.9.3"} \ No newline at end of file