From bff832be02ae107e4f7c4e49c1f7e90a49913a43 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 11:15:32 +0800 Subject: [PATCH 01/12] docs: add whole-project code review and technology roadmap report Fine-grained review of the entire DevLog repo across five subsystems (core data layer, runtime/orchestration, API security, CLI/build/CI, frontend), produced by parallel specialist reviewers. Several findings were empirically reproduced against better-sqlite3 and the shipped dist/cli.js. Catalogs 9 Critical, 30 Important, and a suggestions set spanning data loss in SQLite migrations, a watchdog that re-executes agent turns without a retry cap, broken control-plane gate delivery, CSRF/path- traversal/arbitrary-binary execution on unauthenticated localhost API routes, a non-functional published binary shipping a destructive test-data script, UTC-vs-local cost/date bucketing, and unbounded caches/SSE/poll leaks. Closes with a phased technology roadmap. Baseline at time of review: tsc --noEmit clean, 224/224 tests pass. Co-Authored-By: Claude Fable 5 --- docs/REVIEW-2026-06-10.md | 211 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 docs/REVIEW-2026-06-10.md 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 | From 63de291cae4796c7e4ce3d0b1113b0f0ae0bcf58 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 12:16:37 +0800 Subject: [PATCH 02/12] fix(db): disable FKs during table rebuilds and detect CHECK widening via sqlite_master CR-1: DROP TABLE during the tasks rebuild fired sessions' ON DELETE SET NULL action, silently nulling every session->task link on legacy DBs. Rebuilds now follow the documented SQLite procedure: foreign_keys OFF, column-intersection copy, rename, foreign_key_check, foreign_keys ON. CR-2: the sessions/tasks CHECK-widening probes (UPDATE ... WHERE status='idle') could never throw on a legacy DB, so the constraint was never widened and the catch path would have cascade-deleted session logs and dropped columns. Detection now inspects sqlite_master SQL; the dead tasks probe block is removed and the canonical DDL is single-sourced from db-schema.ts. Co-Authored-By: Claude Fable 5 --- src/core/__tests__/db-migrations.test.ts | 146 +++++++++++++++++ src/core/db-schema.ts | 20 ++- src/core/db.ts | 190 ++++++++++------------- 3 files changed, 243 insertions(+), 113 deletions(-) create mode 100644 src/core/__tests__/db-migrations.test.ts 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/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..d74cb46 100644 --- a/src/core/db.ts +++ b/src/core/db.ts @@ -1,7 +1,7 @@ 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"; import { DEFAULT_AGENT_TEAM_ID, DEFAULT_CODING_AGENT_ID, @@ -46,53 +46,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"]) { @@ -178,38 +134,6 @@ export function getDb(): Database.Database { } 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) { _recovered = true; @@ -242,36 +166,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"); } } From 19b14204bae4f880c8347f65061bef7241548296 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 12:19:56 +0800 Subject: [PATCH 03/12] fix(scripts): stop generate-test-data from deleting real Claude history MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR-9: the test-data generator ran rm -rf ~/.claude/projects at module load — unrecoverably deleting every real Claude Code session log — and shipped in the npm tarball. It now refuses to touch the real history dir without --force, supports DEVLOG_TEST_DATA_DIR for scratch output, only cleans the specific project dirs it generates, and the test harness scripts are excluded from the published package. Co-Authored-By: Claude Fable 5 --- package.json | 5 ++++- scripts/generate-test-data.ts | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index b4cd285..3f2a527 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ }, "files": [ "dist", - "scripts" + "scripts", + "!scripts/generate-test-data.ts", + "!scripts/task-launch-e2e.mjs", + "!scripts/task-launch-e2e-config.mjs" ], "scripts": { "prepare": "husky", 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 }); From 6b53681f8683463f63b2b72933b0016332e4c20f Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 12:31:04 +0800 Subject: [PATCH 04/12] fix(cli): resolve package root robustly from the bundled dist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR-8: tsup bundles the CLI to a single dist/cli.js, so the fixed '../../..' hops from import.meta.dirname resolved above the repo root — 'devlog serve' exited with 'requires running from the DevLog source repo' even when run from it, and setup-statusline/setup-tmux never found the shipped scripts/. Resolution now walks up to the @moose-lab/devlog package.json. The stale force-added dist/ artifacts leave version control and prepublishOnly rebuilds them on publish, so a new version can no longer ship weeks-old code. Co-Authored-By: Claude Fable 5 --- dist/cli.js | 3129 ----------------------- dist/cli.js.map | 1 - package.json | 1 + src/cli/commands/serve.ts | 6 +- src/cli/commands/setup-statusline.ts | 9 +- src/cli/commands/setup-tmux.ts | 11 +- src/cli/lib/package-root.ts | 36 + src/core/__tests__/package-root.test.ts | 58 + tsconfig.tsbuildinfo | 2 +- 9 files changed, 112 insertions(+), 3141 deletions(-) delete mode 100755 dist/cli.js delete mode 100644 dist/cli.js.map create mode 100644 src/cli/lib/package-root.ts create mode 100644 src/core/__tests__/package-root.test.ts 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/package.json b/package.json index 3f2a527..9dd66e6 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ ], "scripts": { "prepare": "husky", + "prepublishOnly": "tsup", "dev": "next dev", "build": "next build", "build:cli": "tsup", 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__/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/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 From fa9604dd55748a673a31b536d7bd51cb1e7ce440 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 14:01:50 +0800 Subject: [PATCH 05/12] feat(security): reject cross-origin and non-local API requests via proxy guard CR-6: no API route validated Origin/Sec-Fetch-Site/Host, so every mutation (task execute, worktree create, gh pr create with the user's credentials) was reachable from any webpage via CSRF or DNS rebinding to 127.0.0.1. A Next.js proxy (Next 16's middleware convention) now rejects requests whose Host is not loopback, and mutating requests carrying cross-origin browser markers. Headerless CLI clients (curl, scripts) remain allowed. This closes the remote trigger for CR-5/CR-7 and IM-19/20/21. Co-Authored-By: Claude Fable 5 --- .../__tests__/request-origin-guard.test.ts | 101 ++++++++++++++++++ src/lib/request-origin-guard.ts | 67 ++++++++++++ src/proxy.ts | 24 +++++ 3 files changed, 192 insertions(+) create mode 100644 src/core/__tests__/request-origin-guard.test.ts create mode 100644 src/lib/request-origin-guard.ts create mode 100644 src/proxy.ts 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/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*", +}; From 1e592a8f5eed3b29524c8158631c6a07cf158633 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 14:15:00 +0800 Subject: [PATCH 06/12] fix(security): validate worktree name and branch refs before filesystem and git use CR-5/IM-22: POST /api/worktrees joined the request-supplied name into a path with only a falsy check, so '../../../../tmp/pwn' materialized a working tree (with repo files) at an attacker-chosen location, and branch values starting with '-' were argument injection into git. Names and refs are now validated at the route (400) and again in createWorktree as defense in depth, the resolved path is asserted to stay inside .worktrees/, and '--' separates git options from paths. Co-Authored-By: Claude Fable 5 --- src/app/api/worktrees/route.ts | 16 ++++- .../__tests__/worktree-validation.test.ts | 62 +++++++++++++++++++ src/core/worktree-manager.ts | 21 ++++++- src/core/worktree-validation.ts | 46 ++++++++++++++ 4 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 src/core/__tests__/worktree-validation.test.ts create mode 100644 src/core/worktree-validation.ts 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/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/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 }; +} From 86454aa4618e5ea7c3032c4771df816884bd7859 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 14:37:27 +0800 Subject: [PATCH 07/12] fix(security): ignore foreign *_BIN overrides and unvalidated base URLs in local-CLI env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR-7: a request body could set CLAUDE_BIN (or any agent's *_BIN) to any existing path — POST {"CLAUDE_BIN":"/bin/sh"} to the unauthenticated connection-test route spawned a shell. *_BIN overrides are now only honored when the file is actually named like the agent's binary, so custom install locations keep working while arbitrary binaries don't. IM-21: request-supplied ANTHROPIC_BASE_URL/OPENAI_BASE_URL values were spread into the child CLI env without validateAgentConnectionBaseUrl, redirecting the agent's provider traffic (prompt exfiltration, SSRF to private hosts). *_BASE_URL env values now pass the same SSRF validation as direct provider base URLs. Co-Authored-By: Claude Fable 5 --- .../__tests__/local-cli-env-hardening.test.ts | 73 ++++++++++++++++++ .../__tests__/process-manager-health.test.ts | 77 ++++++++++++++----- src/core/agent-settings.ts | 25 +++++- src/core/session-runtime-auth.ts | 29 +++++-- 4 files changed, 178 insertions(+), 26 deletions(-) create mode 100644 src/core/__tests__/local-cli-env-hardening.test.ts 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__/process-manager-health.test.ts b/src/core/__tests__/process-manager-health.test.ts index 2ac8129..240d348 100644 --- a/src/core/__tests__/process-manager-health.test.ts +++ b/src/core/__tests__/process-manager-health.test.ts @@ -1,5 +1,8 @@ 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 { SESSION_UNRESPONSIVE_MS, buildClaudeProcessArgs, @@ -236,6 +239,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 +282,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 +327,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/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/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) ?? From d55dad8b38f4c6bf8fbea21ec9d522a439cfb1dc Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 15:41:05 +0800 Subject: [PATCH 08/12] fix(security): validate claude_session_id before filesystem use in VCC IM-19: claude_session_id is parsed from agent stdout (attacker- influenced under the malicious-JSONL threat model) and flowed unvalidated into getJsonlPath + python3 argv + safeRead, letting a traversal id read arbitrary .txt/.jsonl files into the API response. The id is now validated at persist time (process-manager) and at use time (compileSession), with a path-containment assertion against the Claude projects dir. Co-Authored-By: Claude Fable 5 --- src/core/__tests__/vcc-session-id.test.ts | 45 +++++++++++++++++++++++ src/core/process-manager.ts | 11 ++++-- src/core/vcc.ts | 20 +++++++++- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/core/__tests__/vcc-session-id.test.ts 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/process-manager.ts b/src/core/process-manager.ts index 60a342e..dfb68e9 100644 --- a/src/core/process-manager.ts +++ b/src/core/process-manager.ts @@ -35,6 +35,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")) { @@ -1755,8 +1756,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 +1864,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 { 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; From d8cb1a658227825f91fde6be5e5745846f2d6de9 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 16:04:05 +0800 Subject: [PATCH 09/12] fix(runtime): stop the watchdog from killing healthy turns and cap restarts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR-3: writeMessage never bumped lastActivityAt, so any turn with >3min of stdout silence (slow model, long tool call) was SIGKILLed and its user message silently re-executed — with no restart limit, a deterministically slow turn was killed and re-run every 3 minutes forever, duplicating side effects and growing session_messages unboundedly. The watchdog also churned idle persistent sessions. The activity clock now starts at send time and stderr output counts as activity; idle (non-processing) sessions are exempt; and after MAX_WATCHDOG_RESTARTS (2) the turn is failed and its linked task released instead of being re-executed again. Co-Authored-By: Claude Fable 5 --- .../__tests__/process-manager-health.test.ts | 31 +++++++++++ src/core/process-manager.ts | 51 +++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/core/__tests__/process-manager-health.test.ts b/src/core/__tests__/process-manager-health.test.ts index 240d348..14a7a30 100644 --- a/src/core/__tests__/process-manager-health.test.ts +++ b/src/core/__tests__/process-manager-health.test.ts @@ -4,6 +4,7 @@ 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, buildLocalCliProcessLaunch, @@ -68,6 +69,36 @@ 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("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 diff --git a/src/core/process-manager.ts b/src/core/process-manager.ts index dfb68e9..23ba3b3 100644 --- a/src/core/process-manager.ts +++ b/src/core/process-manager.ts @@ -168,19 +168,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( @@ -529,6 +540,7 @@ class ProcessManager { private sessions = new Map(); private messageQueues = new Map(); private providerProcessing = new Set(); + private watchdogRestarts = new Map(); constructor() { const watchdog = setInterval( @@ -563,11 +575,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); @@ -866,6 +906,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 @@ -1086,8 +1127,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 = []; @@ -1896,8 +1940,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 = []; From 59d2a6a820d664e47478b97afd5f72df50f9f850 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 16:17:21 +0800 Subject: [PATCH 10/12] fix(runtime): don't clear control-plane gates until the response is deliverable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CR-4: for plain-stdin agents (codex, gemini, opencode, ...) the original send closes stdin, so when the SIGSTOPped process later hit a gate, resolveGate cleared the persisted gate, emitted gate_resolved + running, and then writeGateResponse silently dropped the answer on the writableEnded guard — the human's response was permanently lost while the UI showed success. resolveGate now peeks the gate first, replaces processes whose stdin was consumed with a fresh one, delivers through writeMessage (protocol-correct stdin.end for EOF-reading runners), and only clears the gate once delivery is possible. IM-9: when ensureProcess fails, resolveGate now returns an actionable error and leaves the gate persisted instead of reporting success on a failed session. Co-Authored-By: Claude Fable 5 --- .../__tests__/control-plane-protocol.test.ts | 43 +++++++ .../__tests__/process-manager-health.test.ts | 22 ++++ src/core/control-plane-protocol.ts | 32 +++-- src/core/process-manager.ts | 117 +++++++++--------- 4 files changed, 148 insertions(+), 66 deletions(-) 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__/process-manager-health.test.ts b/src/core/__tests__/process-manager-health.test.ts index 14a7a30..d2444c4 100644 --- a/src/core/__tests__/process-manager-health.test.ts +++ b/src/core/__tests__/process-manager-health.test.ts @@ -7,6 +7,7 @@ import { MAX_WATCHDOG_RESTARTS, SESSION_UNRESPONSIVE_MS, buildClaudeProcessArgs, + canDeliverGateResponse, buildLocalCliProcessLaunch, needsBrowserApiKeyForWatchdogRestart, parseClaudeBinaryPath, @@ -99,6 +100,27 @@ 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 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/process-manager.ts b/src/core/process-manager.ts index 23ba3b3..d3deb05 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, @@ -201,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, @@ -1280,44 +1294,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); @@ -1337,37 +1369,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, From dc8ca1214c948a81ea8916ceb1f363de985b3e81 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 16:36:06 +0800 Subject: [PATCH 11/12] fix(runtime): persist exit codes, guard stale close handlers, release tasks on orphan recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IM-5: the close handler deleted the session registry entry without checking it still owned it, so after a kill->respawn the stale close evicted the freshly respawned process — leaving a live agent invisible to kill() and the watchdog. Close handlers now verify identity and skip status/exit mutations when a newer process owns the session. IM-6: proc.on('close', code) never wrote the exit code, so sessions.exit_code stayed NULL and task routing read NULL !== 0 as failure — every clean no-change exit was routed to 'blocked'. The exit code is now persisted and NULL is treated explicitly as 'not recorded'. IM-8: recoverOrphanedSessions failed sessions directly, stranding linked tasks 'in_progress' against a dead session forever; it now goes through markSessionFailedAndReleaseLinkedTask so they can be retried. Co-Authored-By: Claude Fable 5 --- src/core/__tests__/db-schema.test.ts | 24 +++++++++++++++++++++++ src/core/__tests__/task-lifecycle.test.ts | 10 ++++++++++ src/core/db.ts | 13 +++++++++--- src/core/process-manager.ts | 22 +++++++++++++++++---- src/core/task-lifecycle.ts | 13 +++++++++++- 5 files changed, 74 insertions(+), 8 deletions(-) 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__/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/db.ts b/src/core/db.ts index d74cb46..9c536b5 100644 --- a/src/core/db.ts +++ b/src/core/db.ts @@ -2,6 +2,9 @@ import Database from "better-sqlite3"; import path from "path"; import fs from "fs"; 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, @@ -290,9 +293,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 d3deb05..768b2e9 100644 --- a/src/core/process-manager.ts +++ b/src/core/process-manager.ts @@ -949,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, @@ -968,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, { @@ -978,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 diff --git a/src/core/task-lifecycle.ts b/src/core/task-lifecycle.ts index 8b0bf11..3c7d10f 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,13 @@ export async function onSessionExit(sessionId: string): Promise { } } + const failedExit = isFailedSessionExit(session.exit_code); + 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); From 537f785aa1931835db9530d568015b6e06d0fa49 Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 11 Jun 2026 17:08:38 +0800 Subject: [PATCH 12/12] chore(review): drop duplicate control-plane migration call, document exit routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses two review follow-ups on #41: the second migrateControlPlaneColumns call in getDb() was redundant (idempotent but confusing), and the clean-exit/no-changes case in onSessionExit is intentionally left to the human — now stated in a comment. Co-Authored-By: Claude Fable 5 --- src/core/db.ts | 1 - src/core/task-lifecycle.ts | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/db.ts b/src/core/db.ts index 9c536b5..6ac5d0a 100644 --- a/src/core/db.ts +++ b/src/core/db.ts @@ -135,7 +135,6 @@ export function getDb(): Database.Database { } catch { // Column already exists } - migrateControlPlaneColumns(_db); // Recover orphaned sessions on first access if (!_recovered) { diff --git a/src/core/task-lifecycle.ts b/src/core/task-lifecycle.ts index 3c7d10f..7d9a257 100644 --- a/src/core/task-lifecycle.ts +++ b/src/core/task-lifecycle.ts @@ -167,6 +167,9 @@ 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 = ?"