@kynver-app/runtime 0.1.118 → 0.1.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/anthropic-credentials.d.ts +9 -0
- package/dist/chat/anthropic-stream.d.ts +43 -0
- package/dist/chat/chat-claim-loop.d.ts +25 -0
- package/dist/chat/delta-batcher.d.ts +13 -0
- package/dist/cli.js +8143 -6989
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts +2 -0
- package/dist/cron/cron-env-file.d.ts +15 -0
- package/dist/cron/cron-id.d.ts +3 -0
- package/dist/cron/cron-install-api.d.ts +27 -0
- package/dist/cron/cron-install-cli.d.ts +2 -0
- package/dist/cron/cron-install-plan.d.ts +32 -0
- package/dist/cron/cron-install-secrets.d.ts +6 -0
- package/dist/cron/cron-install-systemd.d.ts +18 -0
- package/dist/cron/cron-install-verify.d.ts +15 -0
- package/dist/cron/cron-install.d.ts +51 -0
- package/dist/cron/cron-store.d.ts +5 -0
- package/dist/index.js +1349 -197
- package/dist/index.js.map +4 -4
- package/dist/server/cleanup.js.map +2 -2
- package/dist/server/default-repo.js.map +2 -2
- package/dist/server/memory-cost-enforce.js.map +1 -1
- package/dist/server/monitor.js.map +2 -2
- package/dist/server/worker-policy.js.map +2 -2
- package/dist/start.d.ts +7 -0
- package/dist/worktree.d.ts +8 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/util.ts", "../../src/worker-env.ts", "../../src/git.ts", "../../src/path-values.ts", "../../src/default-repo-discovery.ts", "../../src/box-identity.ts", "../../src/bounded-build/meminfo.ts", "../../src/wsl-host.ts", "../../src/disk-gate.ts", "../../src/run-store.ts", "../../src/run-worker-index.ts", "../../src/heartbeat-final-result.ts", "../../src/heartbeat.ts", "../../src/repo-search.ts", "../../src/shell-command-outcome.ts", "../../src/stream.ts", "../../src/exit-classify.ts", "../../src/exited-salvage.ts", "../../src/landing-gate.ts", "../../src/worker-final-result-embed.ts", "../../src/landing-contract-gate.ts", "../../src/status.ts", "../../src/harness-worker-active.ts", "../../src/resource-gate.ts", "../../src/worker-cap-source.ts", "../../src/config.ts", "../../src/paths.ts", "../../src/cleanup.ts", "../../src/cleanup-guards.ts", "../../src/cleanup-index-status.ts", "../../src/cleanup-build-cache-paths.ts", "../../src/cleanup-guards-helpers.ts", "../../src/cleanup-worktree-salvage.ts", "../../src/finalize.ts", "../../src/cleanup-run-liveness.ts", "../../src/cleanup-completion-blocker.ts", "../../src/cleanup-types.ts", "../../src/cleanup-evidence.ts", "../../src/cleanup-run-directory.ts", "../../src/cleanup-active-worktrees.ts", "../../src/run-metadata-retention.ts", "../../src/default-repo.ts", "../../src/worker-metadata-paths.ts", "../../src/cleanup-execute.ts", "../../src/cleanup-dir-size.ts", "../../src/cleanup-remove-path.ts", "../../src/cleanup-path-ownership.ts", "../../src/cleanup-privileged-remove.ts", "../../src/cleanup-harness-path-validate.ts", "../../src/cleanup-scan.ts", "../../src/cleanup-dependency-scan.ts", "../../src/cleanup-duplicate-worktrees.ts", "../../src/cleanup-worktree-index.ts", "../../src/cleanup-retention-config.ts", "../../src/cleanup-orphan-safety.ts", "../../src/harness-storage-snapshot.ts", "../../src/cleanup-harness-roots.ts", "../../src/cleanup-disk-pressure.ts", "../../src/cleanup-progress.ts", "../../src/cleanup-git-rev-cache.ts", "../../src/cleanup-git-status-cache.ts", "../../src/cleanup-run-terminal-cache.ts", "../../src/cleanup-summary.ts"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\n\r\nexport function fail(message: string): never {\r\n console.error(message);\r\n process.exit(1);\r\n}\r\n\r\n/** Avoid flashing a visible console on Windows when spawning worker/sidecar children. */\r\nexport function hiddenSpawnOptions<T extends Record<string, unknown>>(opts: T): T {\r\n if (process.platform !== \"win32\") return opts;\r\n return { windowsHide: true, ...opts };\r\n}\r\n\r\nexport function required(value: string | undefined, name: string): string {\r\n if (!value) fail(`missing ${name}`);\r\n return value;\r\n}\r\n\r\nexport function safeJson(line: string): unknown {\r\n try {\r\n return JSON.parse(line);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function readJson<T>(file: string, fallback?: T): T {\r\n try {\r\n return JSON.parse(readFileSync(file, \"utf8\")) as T;\r\n } catch (error) {\r\n if (arguments.length > 1) return fallback as T;\r\n fail(`failed to read ${file}: ${(error as Error).message}`);\r\n }\r\n}\r\n\r\nexport function writeJson(file: string, value: unknown): void {\r\n mkdirSync(path.dirname(file), { recursive: true });\r\n writeFileSync(file, `${JSON.stringify(value, null, 2)}\\n`);\r\n}\r\n\r\nexport function safeSlug(value: string | undefined): string {\r\n return (\r\n String(value || \"\")\r\n .toLowerCase()\r\n .replace(/[^a-z0-9._-]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\") || \"worker\"\r\n );\r\n}\r\n\r\nexport function timestampSlug(name: string): string {\r\n return safeSlug(`${new Date().toISOString().replace(/[-:]/g, \"\").replace(/\\..+/, \"Z\")}-${name}`);\r\n}\r\n\r\nexport function splitCsv(value: string | undefined): string[] {\r\n return value ? String(value).split(\",\").map((item) => item.trim()).filter(Boolean) : [];\r\n}\r\n\r\nexport function trimTrailingSlash(url: string): string {\r\n return String(url).replace(/\\/+$/, \"\");\r\n}\r\n\r\nexport function oneLine(value: string): string {\r\n return String(value || \"\")\r\n .replace(/\\s+/g, \" \")\r\n .trim();\r\n}\r\n\r\nexport function fileSize(file: string): number {\r\n try {\r\n return statSync(file).size;\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nexport function fileMtime(file: string): string | null {\r\n try {\r\n return statSync(file).mtime.toISOString();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function tailFile(file: string, lines: number): string {\r\n if (!existsSync(file)) return \"\";\r\n const data = readFileSync(file, \"utf8\");\r\n return data.split(\"\\n\").slice(-lines).join(\"\\n\");\r\n}\r\n\r\nexport function readMaybeFile(file: string | undefined): string {\r\n return file ? readFileSync(path.resolve(file), \"utf8\") : \"\";\r\n}\r\n\r\nexport function listRunIds(runsDir: string): string[] {\r\n if (!existsSync(runsDir)) return [];\r\n return readdirSync(runsDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n}\r\n\r\nexport function sleepMs(ms: number): void {\r\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\r\n}\r\n\r\n/** Non-blocking sleep for async loops (daemon backoff, interruptible shutdown). */\r\nexport function sleepMsAsync(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport function isPidAlive(pid: number | undefined): boolean {\r\n if (!pid) return false;\r\n try {\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function killWorkerProcess(pid: number, signal: NodeJS.Signals): void {\r\n try {\r\n process.kill(-pid, signal);\r\n } catch {\r\n process.kill(pid, signal);\r\n }\r\n}\r\n\r\nexport function latestIso(values: Array<string | null | undefined>): string | null {\r\n let best: string | null = null;\r\n let bestMs = -Infinity;\r\n for (const value of values) {\r\n if (!value) continue;\r\n const ms = Date.parse(value);\r\n if (Number.isFinite(ms) && ms > bestMs) {\r\n bestMs = ms;\r\n best = value;\r\n }\r\n }\r\n return best;\r\n}\r\n\r\nexport function secsAgo(ms: number): number {\r\n return Math.max(0, Math.round((Date.now() - ms) / 1000));\r\n}\r\n", "/**\r\n * Worker spawn env scrub \u2014 harness workers must not inherit host deployment secrets.\r\n */\r\n\r\n/** Exact env keys that must never reach a worker child process. */\r\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\r\n \"ANTHROPIC_API_KEY\",\r\n \"ANALYST_API_KEY\",\r\n \"RECRUITER_API_KEY\",\r\n \"AUTH_SECRET\",\r\n \"NEXTAUTH_SECRET\",\r\n \"DATABASE_URL\",\r\n \"PRODUCTION_DATABASE_URL\",\r\n \"KYNVER_PRODUCTION_DATABASE_URL\",\r\n \"REDIS_URL\",\r\n \"GOOGLE_CLIENT_SECRET\",\r\n \"GITHUB_CLIENT_SECRET\",\r\n \"KYNVER_API_KEY\",\r\n \"KYNVER_SERVICE_SECRET\",\r\n \"KYNVER_RUNTIME_SECRET\",\r\n \"KYNVER_CRON_SECRET\",\r\n \"OPENCLAW_CRON_SECRET\",\r\n \"QSTASH_TOKEN\",\r\n \"QSTASH_CURRENT_SIGNING_KEY\",\r\n \"QSTASH_NEXT_SIGNING_KEY\",\r\n \"TOOL_SECRETS_KEK\",\r\n \"TOOL_EXECUTOR_DISPATCH_SECRET\",\r\n \"CLOUDFLARE_API_TOKEN\",\r\n \"STRIPE_SECRET_KEY\",\r\n \"STRIPE_WEBHOOK_SECRET\",\r\n \"STRIPE_IDENTITY_WEBHOOK_SECRET\",\r\n \"VOYAGE_API_KEY\",\r\n \"PERPLEXITY_API_KEY\",\r\n \"FRED_API_KEY\",\r\n \"FMP_API_KEY\",\r\n \"CURSOR_API_KEY\",\r\n] as const;\r\n\r\nconst FORBIDDEN_KEY_SET = new Set<string>(FORBIDDEN_WORKER_ENV_KEYS);\r\n\r\n/** Keys matching these suffixes are stripped (case-sensitive). */\r\nconst FORBIDDEN_SUFFIXES = [\"_SECRET\", \"_API_KEY\"] as const;\r\n\r\nexport function isForbiddenWorkerEnvKey(key: string): boolean {\r\n if (FORBIDDEN_KEY_SET.has(key)) return true;\r\n return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));\r\n}\r\n\r\nexport function listForbiddenWorkerEnvKeys(env: NodeJS.ProcessEnv): string[] {\r\n return Object.keys(env).filter(isForbiddenWorkerEnvKey).sort();\r\n}\r\n\r\nexport function scrubWorkerEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\r\n const next = { ...env };\r\n for (const key of Object.keys(next)) {\r\n if (isForbiddenWorkerEnvKey(key)) delete next[key];\r\n }\r\n return next;\r\n}\r\n\r\nexport interface WorkerEnvAudit {\r\n forbiddenPresent: string[];\r\n safe: boolean;\r\n}\r\n\r\nexport function auditWorkerEnv(env: NodeJS.ProcessEnv): WorkerEnvAudit {\r\n const forbiddenPresent = listForbiddenWorkerEnvKeys(env);\r\n return { forbiddenPresent, safe: forbiddenPresent.length === 0 };\r\n}\r\n\r\n/** @deprecated Use {@link scrubWorkerEnv} \u2014 kept for existing imports from git.ts */\r\nexport function scrubClaudeEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\r\n return scrubWorkerEnv(env);\r\n}\r\n", "import { spawnSync } from \"node:child_process\";\r\nimport { fail, hiddenSpawnOptions } from \"./util.js\";\r\n\r\nexport interface GitOptions {\r\n allowFailure?: boolean;\r\n throwError?: boolean;\r\n}\r\n\r\nexport function git(cwd: string, args: string[], options: GitOptions = {}): string {\r\n const res = spawnSync(\r\n \"git\",\r\n args,\r\n hiddenSpawnOptions({ cwd, encoding: \"utf8\" as const }),\r\n );\r\n if (res.status !== 0 && !options.allowFailure) {\r\n const message = `git ${args.join(\" \")} failed: ${res.stderr || res.stdout}`;\r\n if (options.throwError) throw new Error(message);\r\n fail(message);\r\n }\r\n return res.stdout || \"\";\r\n}\r\n\r\nexport function ensureGitRepo(repo: string): void {\r\n git(repo, [\"rev-parse\", \"--show-toplevel\"]);\r\n}\r\n\r\nexport function gitStatusShort(worktreePath: string): string[] {\r\n return git(worktreePath, [\"status\", \"--short\"], { allowFailure: true })\r\n .split(\"\\n\")\r\n .map((line) => line.trim())\r\n .filter(Boolean);\r\n}\r\n\r\nexport interface GitCaptureResult {\r\n status: number | null;\r\n stdout: string;\r\n stderr: string;\r\n error: string | null;\r\n}\r\n\r\nexport function gitCapture(cwd: string, args: string[]): GitCaptureResult {\r\n try {\r\n const res = spawnSync(\r\n \"git\",\r\n args,\r\n hiddenSpawnOptions({ cwd, encoding: \"utf8\" as const }),\r\n );\r\n return {\r\n status: res.status,\r\n stdout: res.stdout || \"\",\r\n stderr: res.stderr || \"\",\r\n error: res.error ? res.error.message : null,\r\n };\r\n } catch (error) {\r\n return {\r\n status: null,\r\n stdout: \"\",\r\n stderr: \"\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\nexport function gitIsAncestor(\r\n cwd: string,\r\n ancestor: string,\r\n descendant: string,\r\n): { isAncestor: boolean | null; error: string | null } {\r\n const res = gitCapture(cwd, [\"merge-base\", \"--is-ancestor\", ancestor, descendant]);\r\n if (res.status === 0) return { isAncestor: true, error: null };\r\n if (res.status === 1) return { isAncestor: false, error: null };\r\n return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };\r\n}\r\n\r\nexport type GitAncestryRelation = \"synced\" | \"merged\" | \"ahead\" | \"diverged\" | \"unknown\";\r\n\r\nexport interface GitAncestry {\r\n checked: boolean;\r\n base: string;\r\n head: string | null;\r\n baseHead: string | null;\r\n baseIsAncestorOfHead: boolean | null;\r\n headIsAncestorOfBase: boolean | null;\r\n relation: GitAncestryRelation;\r\n error?: string;\r\n}\r\n\r\nexport interface GitAncestryOptions {\r\n /** Branch or ref name (e.g. origin/main). Used when baseCommit is unset. */\r\n base?: string;\r\n /** Pinned SHA the worktree was created from \u2014 preferred over a moving branch ref. */\r\n baseCommit?: string;\r\n}\r\n\r\nexport function computeGitAncestry(worktreePath: string, baseOrOptions: string | GitAncestryOptions = \"origin/main\"): GitAncestry {\r\n const options: GitAncestryOptions =\r\n typeof baseOrOptions === \"string\" ? { base: baseOrOptions } : baseOrOptions;\r\n const baseLabel = options.baseCommit?.trim() || options.base?.trim() || \"origin/main\";\r\n const pinnedBaseCommit = options.baseCommit?.trim() || null;\r\n\r\n if (!worktreePath) {\r\n return unknownAncestry(baseLabel, \"missing worktree path\");\r\n }\r\n\r\n const head = gitCapture(worktreePath, [\"rev-parse\", \"HEAD\"]);\r\n if (head.status !== 0) {\r\n return unknownAncestry(baseLabel, head.error || head.stderr || head.stdout || \"failed to resolve HEAD\");\r\n }\r\n\r\n let baseSha: string;\r\n if (pinnedBaseCommit) {\r\n baseSha = pinnedBaseCommit;\r\n } else {\r\n const baseHead = gitCapture(worktreePath, [\"rev-parse\", baseLabel]);\r\n if (baseHead.status !== 0) {\r\n return unknownAncestry(\r\n baseLabel,\r\n baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${baseLabel}`,\r\n head.stdout.trim(),\r\n );\r\n }\r\n baseSha = baseHead.stdout.trim();\r\n }\r\n\r\n const headSha = head.stdout.trim();\r\n if (headSha === baseSha) {\r\n return {\r\n checked: true,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: true,\r\n headIsAncestorOfBase: true,\r\n relation: \"synced\",\r\n };\r\n }\r\n\r\n const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);\r\n const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);\r\n const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || undefined;\r\n if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {\r\n return {\r\n checked: false,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,\r\n headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,\r\n relation: \"unknown\",\r\n ...(error ? { error } : {}),\r\n };\r\n }\r\n\r\n const relation: GitAncestryRelation = baseIsAncestorOfHead.isAncestor\r\n ? \"ahead\"\r\n : headIsAncestorOfBase.isAncestor\r\n ? \"merged\"\r\n : \"diverged\";\r\n\r\n return {\r\n checked: true,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,\r\n headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,\r\n relation,\r\n ...(error ? { error } : {}),\r\n };\r\n}\r\n\r\nfunction unknownAncestry(base: string, error: string, head: string | null = null): GitAncestry {\r\n return {\r\n checked: false,\r\n base,\r\n head,\r\n baseHead: null,\r\n baseIsAncestorOfHead: null,\r\n headIsAncestorOfBase: null,\r\n relation: \"unknown\",\r\n error,\r\n };\r\n}\r\n\r\nexport { scrubClaudeEnv, scrubWorkerEnv } from \"./worker-env.js\";\r\n", "import { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\n\r\nexport function expandHomePath(value: string): string {\r\n if (value === \"~\") return homedir();\r\n if (value.startsWith(\"~/\") || value.startsWith(\"~\\\\\")) {\r\n return path.join(homedir(), value.slice(2));\r\n }\r\n return value;\r\n}\r\n\r\nexport function resolveUserPath(value: string): string {\r\n return path.resolve(expandHomePath(value));\r\n}\r\n\r\nexport function redactHomePath(value: string): string {\r\n const expanded = expandHomePath(value);\r\n const resolved = path.resolve(expanded);\r\n const home = path.resolve(homedir());\r\n\r\n if (resolved === home) return \"~\";\r\n if (resolved.startsWith(`${home}${path.sep}`)) {\r\n return `~/${path.relative(home, resolved).split(path.sep).join(\"/\")}`;\r\n }\r\n\r\n const posix = resolved.replace(/\\\\/g, \"/\");\r\n const redacted = posix\r\n .replace(/^\\/home\\/[^/]+(?=\\/|$)/, \"~\")\r\n .replace(/^\\/Users\\/[^/]+(?=\\/|$)/, \"~\")\r\n // Windows resolves Unix-style `/home/...` paths to `C:\\home\\...`.\r\n .replace(/^[A-Za-z]:\\/home\\/[^/]+(?=\\/|$)/i, \"~\")\r\n .replace(/^[A-Za-z]:\\/Users\\/[^/]+(?=\\/|$)/i, \"~\");\r\n return redacted;\r\n}\r\n\r\n/** User-facing path strings (doctor JSON, setup output). */\r\nexport function displayUserPath(value: string): string {\r\n return redactHomePath(value);\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport { gitCapture } from \"./git.js\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\n\r\nexport type DefaultRepoDiscoverySource =\r\n | \"cwd_git\"\r\n | \"runtime_checkout\"\r\n | \"well_known_path\";\r\n\r\nexport interface DiscoveredDefaultRepo {\r\n repo: string;\r\n source: DefaultRepoDiscoverySource;\r\n}\r\n\r\nconst WELL_KNOWN_REPO_DIRS = [\r\n \"Kynver\",\r\n \"repos/Kynver\",\r\n \"repos/kynver-source-main\",\r\n \"code/Kynver\",\r\n \"projects/Kynver\",\r\n] as const;\r\n\r\nfunction readPackageName(repoRoot: string): string | null {\r\n const pkgPath = path.join(repoRoot, \"package.json\");\r\n if (!existsSync(pkgPath)) return null;\r\n try {\r\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { name?: string };\r\n return typeof pkg.name === \"string\" ? pkg.name.trim() : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function isKynverMonorepoRoot(repoRoot: string): boolean {\r\n return readPackageName(repoRoot) === \"kynver\";\r\n}\r\n\r\nexport function gitRepoRoot(startDir: string): string | null {\r\n const resolvedStart = path.resolve(startDir);\r\n if (!existsSync(resolvedStart)) return null;\r\n const probe = gitCapture(resolvedStart, [\"rev-parse\", \"--show-toplevel\"]);\r\n if (probe.status !== 0) return null;\r\n const root = probe.stdout.trim();\r\n return root.length ? path.resolve(root) : null;\r\n}\r\n\r\nfunction resolveRuntimePackageRoot(moduleUrl: string = import.meta.url): string | null {\r\n let dir = path.dirname(fileURLToPath(moduleUrl));\r\n for (let depth = 0; depth < 8; depth += 1) {\r\n const pkgPath = path.join(dir, \"package.json\");\r\n if (existsSync(pkgPath)) {\r\n try {\r\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { name?: string };\r\n if (pkg.name === \"@kynver-app/runtime\") return dir;\r\n } catch {\r\n // continue walking\r\n }\r\n }\r\n const parent = path.dirname(dir);\r\n if (parent === dir) break;\r\n dir = parent;\r\n }\r\n return null;\r\n}\r\n\r\nfunction pushCandidate(\r\n seen: Set<string>,\r\n out: DiscoveredDefaultRepo[],\r\n repo: string | null,\r\n source: DefaultRepoDiscoverySource,\r\n): void {\r\n if (!repo) return;\r\n const resolved = path.resolve(repo);\r\n if (seen.has(resolved)) return;\r\n if (!isKynverMonorepoRoot(resolved)) return;\r\n seen.add(resolved);\r\n out.push({ repo: resolved, source });\r\n}\r\n\r\nexport function discoverDefaultRepoCandidates(opts?: {\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}): DiscoveredDefaultRepo[] {\r\n const cwd = opts?.cwd ?? process.cwd();\r\n const seen = new Set<string>();\r\n const candidates: DiscoveredDefaultRepo[] = [];\r\n\r\n pushCandidate(seen, candidates, gitRepoRoot(cwd), \"cwd_git\");\r\n\r\n const runtimePkgRoot = resolveRuntimePackageRoot(opts?.runtimeModuleUrl ?? import.meta.url);\r\n if (runtimePkgRoot) {\r\n pushCandidate(seen, candidates, gitRepoRoot(runtimePkgRoot), \"runtime_checkout\");\r\n }\r\n\r\n const home = homedir();\r\n for (const rel of WELL_KNOWN_REPO_DIRS) {\r\n pushCandidate(seen, candidates, resolveUserPath(path.join(home, rel)), \"well_known_path\");\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nexport function discoverDefaultRepo(opts?: {\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}): DiscoveredDefaultRepo | null {\r\n return discoverDefaultRepoCandidates(opts)[0] ?? null;\r\n}\r\n", "import type { KynverUserConfig } from \"./config.js\";\r\n\r\nexport type WorkerPoolBoxKind = \"ghost\" | \"forge\";\r\n\r\nexport type BoxKindSource = \"config\" | \"env\" | \"default\";\r\n\r\nexport interface ResolvedBoxIdentity {\r\n boxKind: WorkerPoolBoxKind;\r\n source: BoxKindSource;\r\n /** True when identity would have been inferred from KYNVER_AGENT_OS_SLUG without an explicit box kind. */\r\n slugInferenceBlocked: boolean;\r\n warnings: string[];\r\n}\r\n\r\n/** Normalize host/box labels to ghost | forge for worker-pool attribution. */\r\nexport function normalizeWorkerPoolBoxKind(raw: string | null | undefined): WorkerPoolBoxKind {\r\n const kind = (raw ?? \"\").trim().toLowerCase();\r\n if (kind === \"ghost\" || kind === \"forge\") return kind;\r\n if (kind.includes(\"forge\")) return \"forge\";\r\n if (kind.includes(\"ghost\") || kind.includes(\"openclaw\")) return \"ghost\";\r\n return \"forge\";\r\n}\r\n\r\nfunction trimEnv(env: NodeJS.ProcessEnv, key: string): string | null {\r\n const value = env[key]?.trim();\r\n return value || null;\r\n}\r\n\r\n/**\r\n * Resolve physical box identity for capacity snapshots and daemon policy.\r\n * Never maps AgentOS workspace slug alone to box kind \u2014 Forge installs must set\r\n * `boxKind` in ~/.kynver/config.json or `KYNVER_BOX_KIND`.\r\n */\r\nexport function resolveBoxIdentity(\r\n env: NodeJS.ProcessEnv = process.env,\r\n config: Pick<KynverUserConfig, \"boxKind\"> = {},\r\n): ResolvedBoxIdentity {\r\n const warnings: string[] = [];\r\n const configKind = config.boxKind?.trim();\r\n if (configKind) {\r\n return {\r\n boxKind: normalizeWorkerPoolBoxKind(configKind),\r\n source: \"config\",\r\n slugInferenceBlocked: false,\r\n warnings,\r\n };\r\n }\r\n\r\n const envKind = trimEnv(env, \"KYNVER_BOX_KIND\");\r\n if (envKind) {\r\n return {\r\n boxKind: normalizeWorkerPoolBoxKind(envKind),\r\n source: \"env\",\r\n slugInferenceBlocked: false,\r\n warnings,\r\n };\r\n }\r\n\r\n const agentOsSlug = trimEnv(env, \"KYNVER_AGENT_OS_SLUG\");\r\n if (agentOsSlug) {\r\n warnings.push(\r\n `KYNVER_AGENT_OS_SLUG=${agentOsSlug} is a workspace slug, not box identity \u2014 set boxKind via \\`kynver setup --box-kind forge|ghost\\` or KYNVER_BOX_KIND (defaulting box kind to forge)`,\r\n );\r\n }\r\n\r\n return {\r\n boxKind: \"forge\",\r\n source: \"default\",\r\n slugInferenceBlocked: Boolean(agentOsSlug),\r\n warnings,\r\n };\r\n}\r\n\r\nexport function resolveBoxKindFromConfig(\r\n config: Pick<KynverUserConfig, \"boxKind\"> = {},\r\n env: NodeJS.ProcessEnv = process.env,\r\n): WorkerPoolBoxKind {\r\n return resolveBoxIdentity(env, config).boxKind;\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport os from \"node:os\";\r\n\r\n/**\r\n * Truly-usable memory. On Linux, prefer /proc/meminfo MemAvailable; fall back to\r\n * os.freemem() elsewhere (same semantics as resource-gate).\r\n */\r\nexport function readMemAvailableBytes(meminfoText?: string): number {\r\n if (meminfoText !== undefined) {\r\n const match = meminfoText.match(/^MemAvailable:\\s+(\\d+)\\s*kB/m);\r\n if (match) return Number(match[1]) * 1024;\r\n return os.freemem();\r\n }\r\n if (process.platform === \"linux\") {\r\n try {\r\n const meminfo = readFileSync(\"/proc/meminfo\", \"utf8\");\r\n const match = meminfo.match(/^MemAvailable:\\s+(\\d+)\\s*kB/m);\r\n if (match) return Number(match[1]) * 1024;\r\n } catch {\r\n // fall through\r\n }\r\n }\r\n return os.freemem();\r\n}\r\n", "import { existsSync, readFileSync, statfsSync } from \"node:fs\";\r\n\r\n/**\r\n * WSL host disk probe.\r\n *\r\n * Under WSL, the runtime VHDX (mounted at `/`) grows dynamically into the\r\n * Windows host C: drive. When Windows C: fills up, the VHDX cannot expand:\r\n * writes return SIGBUS, workers exit 135, and the Vmmem VM degrades while\r\n * the Linux-side `statfs /` still reports plenty of free space inside the\r\n * VHDX. This module gives the harness a cheap signal for that pressure so\r\n * it can block dispatch *before* a large npm install/build pushes Windows\r\n * C: into the ground.\r\n */\r\n\r\n/** Default warn threshold for the Windows host disk (25 GiB free). */\r\nexport const DEFAULT_WSL_HOST_WARN_FREE_BYTES = 25 * 1024 * 1024 * 1024;\r\n/** Default critical threshold for the Windows host disk (12 GiB free). Below\r\n * this, large rebuilds have been observed to trigger SIGBUS / exit 135 on\r\n * WSL when the VHDX cannot grow further. */\r\nexport const DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES = 12 * 1024 * 1024 * 1024;\r\n/** Default Windows host mount point under WSL. Overridable via env or option. */\r\nexport const DEFAULT_WSL_HOST_MOUNT = \"/mnt/c\";\r\n\r\nexport interface WslHostDiskShape {\r\n ok: boolean;\r\n /** Mount point that was probed. */\r\n path: string;\r\n freeBytes: number;\r\n totalBytes: number;\r\n usedPercent: number;\r\n warnBelowBytes: number;\r\n criticalBelowBytes: number;\r\n /** Human-readable explanation when the host disk is under pressure. */\r\n reason: string | null;\r\n /** True when the probe itself failed (mount missing, statfs error). */\r\n probeError: string | null;\r\n}\r\n\r\n/**\r\n * Cheap WSL detection. Reads `/proc/sys/kernel/osrelease` (kernel string\r\n * contains \"microsoft\" / \"WSL2\" on Microsoft's WSL kernel) and falls back\r\n * to `/proc/version`. Both reads are one-shot and gated by `existsSync`,\r\n * so non-Linux hosts return false without throwing.\r\n */\r\nexport function isWslHost(): boolean {\r\n if (process.platform !== \"linux\") return false;\r\n for (const probe of [\"/proc/sys/kernel/osrelease\", \"/proc/version\"]) {\r\n try {\r\n if (!existsSync(probe)) continue;\r\n const text = readFileSync(probe, \"utf8\");\r\n if (/microsoft|wsl/i.test(text)) return true;\r\n } catch {\r\n // ignore \u2014 try the next probe path\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport interface ObserveWslHostDiskOptions {\r\n /** Override the Windows host mount path (e.g. `/mnt/d`). Falls back to\r\n * `KYNVER_WSL_HOST_MOUNT` env, then `/mnt/c`. */\r\n wslHostMount?: string;\r\n wslHostFreeWarnBytes?: number;\r\n wslHostFreeCriticalBytes?: number;\r\n /** Override WSL detection for tests / cross-platform CI:\r\n * `true` \u2192 treat host as WSL; `false` \u2192 treat host as non-WSL;\r\n * `undefined` \u2192 autodetect via `isWslHost()`. */\r\n forceWsl?: boolean;\r\n /** Test seam \u2014 swap in a fake statfs. */\r\n statfs?: (path: string) => { bavail: bigint | number; blocks: bigint | number; bsize: bigint | number };\r\n}\r\n\r\n/**\r\n * Probe the Windows host disk under WSL. Returns `null` when this host is\r\n * not WSL (so callers can treat the field as optional in the gate output).\r\n * When WSL but the mount is unreachable, returns a `probeError` row with\r\n * `ok = false` rather than throwing \u2014 the gate must still block dispatch\r\n * because we can't prove the host disk is healthy.\r\n */\r\nexport function observeWslHostDisk(\r\n options: ObserveWslHostDiskOptions = {},\r\n): WslHostDiskShape | null {\r\n const wsl = options.forceWsl === undefined ? isWslHost() : options.forceWsl;\r\n if (!wsl) return null;\r\n\r\n const path =\r\n options.wslHostMount?.trim() ||\r\n process.env.KYNVER_WSL_HOST_MOUNT?.trim() ||\r\n DEFAULT_WSL_HOST_MOUNT;\r\n const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;\r\n const criticalBelowBytes =\r\n options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;\r\n\r\n const statfs = options.statfs ?? statfsSync;\r\n let stats: { bavail: bigint | number; blocks: bigint | number; bsize: bigint | number };\r\n try {\r\n stats = statfs(path);\r\n } catch (error) {\r\n return {\r\n ok: false,\r\n path,\r\n freeBytes: 0,\r\n totalBytes: 0,\r\n usedPercent: 100,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n reason: `Windows host disk probe failed at ${path}: ${(error as Error).message}`,\r\n probeError: (error as Error).message,\r\n };\r\n }\r\n\r\n const freeBytes = Number(stats.bavail) * Number(stats.bsize);\r\n const totalBytes = Number(stats.blocks) * Number(stats.bsize);\r\n const usedPercent = totalBytes > 0 ? ((totalBytes - freeBytes) / totalBytes) * 100 : 100;\r\n const lowFree = freeBytes < warnBelowBytes;\r\n const criticalFree = freeBytes < criticalBelowBytes;\r\n const ok = !lowFree && !criticalFree;\r\n\r\n const freeGiB = (freeBytes / (1024 * 1024 * 1024)).toFixed(1);\r\n let reason: string | null = null;\r\n if (!ok) {\r\n const tag = criticalFree ? \"critical\" : \"warning\";\r\n reason =\r\n `Windows host disk ${path} at ${tag}: ${freeGiB} GiB free ` +\r\n `(<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); ` +\r\n `WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;\r\n }\r\n\r\n return {\r\n ok,\r\n path,\r\n freeBytes,\r\n totalBytes,\r\n usedPercent,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n reason,\r\n probeError: null,\r\n };\r\n}\r\n\r\n/**\r\n * Short operator recovery hint embedded in gate reasons so AgentOS evidence\r\n * surfaces actionable steps without a doc lookup. Keep terse \u2014 full runbook\r\n * lives at `docs/runbooks/wsl-disk-pressure.md`.\r\n */\r\nexport function summarizeWslRecoverySteps(): string {\r\n return (\r\n \"Recovery: \" +\r\n \"1) free Windows C: (empty Recycle Bin / Storage Sense / clear %TEMP%); \" +\r\n \"2) shut down WSL (`wsl --shutdown`) then compact the VHDX (`Optimize-VHD` or `diskpart compact vdisk`); \" +\r\n \"3) clear local node_modules / .next / harness worktrees before restarting workers. \" +\r\n \"Full runbook: docs/runbooks/wsl-disk-pressure.md.\"\r\n );\r\n}\r\n", "import { statfsSync } from \"node:fs\";\r\nimport type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport {\r\n observeWslHostDisk,\r\n type ObserveWslHostDiskOptions,\r\n type WslHostDiskShape,\r\n} from \"./wsl-host.js\";\r\n\r\nconst DEFAULT_WARN_FREE_BYTES = 30 * 1024 * 1024 * 1024;\r\nconst DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;\r\nconst DEFAULT_MAX_USED_PERCENT = 80;\r\nconst DEFAULT_HARD_MAX_USED_PERCENT = 90;\r\n\r\nexport interface ObserveDiskGateInput {\r\n diskPath?: string;\r\n diskFreeWarnBytes?: number;\r\n diskFreeCriticalBytes?: number;\r\n diskMaxUsedPercent?: number;\r\n diskHardMaxUsedPercent?: number;\r\n /** Opt-out for the WSL host disk probe \u2014 leave `false`/undefined by\r\n * default so we always check `/mnt/c` under WSL. */\r\n skipWslHostCheck?: boolean;\r\n wslHost?: ObserveWslHostDiskOptions;\r\n}\r\n\r\nexport function observeRunnerDiskGate(input: ObserveDiskGateInput = {}): DispatchNextDiskGateShape {\r\n const path = input.diskPath?.trim() || \"/\";\r\n const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;\r\n const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;\r\n const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;\r\n const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;\r\n\r\n const stats = statfsSync(path);\r\n const freeBytes = Number(stats.bavail) * Number(stats.bsize);\r\n const totalBytes = Number(stats.blocks) * Number(stats.bsize);\r\n const usedPercent = totalBytes > 0 ? ((totalBytes - freeBytes) / totalBytes) * 100 : 100;\r\n const lowFree = freeBytes < warnBelowBytes;\r\n const criticalFree = freeBytes < criticalBelowBytes;\r\n const highUse = usedPercent > maxUsedPercent;\r\n const hardHighUse = usedPercent > hardMaxUsedPercent;\r\n const localOk = !lowFree && !criticalFree && !highUse && !hardHighUse;\r\n\r\n // WSL guard: the VHDX (mounted at `/`) grows into Windows C:; a healthy\r\n // local statfs is meaningless if the host disk is about to refuse writes.\r\n const wslHost: WslHostDiskShape | null = input.skipWslHostCheck\r\n ? null\r\n : observeWslHostDisk(input.wslHost);\r\n\r\n const ok = localOk && (wslHost ? wslHost.ok : true);\r\n\r\n let reason: string | null = null;\r\n if (!ok) {\r\n reason = [\r\n criticalFree ? `free space below critical ${criticalBelowBytes} bytes` : null,\r\n lowFree ? `free space below warning ${warnBelowBytes} bytes` : null,\r\n hardHighUse ? `used percent above hard cap ${hardMaxUsedPercent}%` : null,\r\n highUse ? `used percent above cap ${maxUsedPercent}%` : null,\r\n wslHost && !wslHost.ok ? wslHost.reason : null,\r\n ]\r\n .filter(Boolean)\r\n .join(\"; \");\r\n }\r\n\r\n return {\r\n ok,\r\n path,\r\n freeBytes,\r\n totalBytes,\r\n usedPercent,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n maxUsedPercent,\r\n hardMaxUsedPercent,\r\n reason,\r\n wslHost,\r\n };\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { getHarnessPaths, harnessRunsDir, runDir as runDirPath } from \"./paths.js\";\r\nimport { readJson, safeSlug, writeJson } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport interface HarnessRunRecord {\r\n id: string;\r\n name: string;\r\n repo: string;\r\n base: string;\r\n baseCommit: string;\r\n status: string;\r\n createdAt: string;\r\n workers: Record<string, { workerDir: string; statusPath: string }>;\r\n}\r\n\r\nexport function getPaths() {\r\n return getHarnessPaths();\r\n}\r\n\r\nexport function loadRun(id: string): HarnessRunRecord {\r\n const { runsDir } = getPaths();\r\n return readJson<HarnessRunRecord>(path.join(runDirPath(runsDir, safeSlug(id)), \"run.json\"));\r\n}\r\n\r\n/**\r\n * Load every run record on disk. Used for global, cross-run accounting (the\r\n * resource gate must see workers from ALL runs, and stale-run finalization\r\n * iterates the whole set). Unreadable/partial run dirs are skipped.\r\n */\r\nexport function listRunRecords(): HarnessRunRecord[] {\r\n const { runsDir } = getPaths();\r\n return listRunRecordsAt(runsDir);\r\n}\r\n\r\nexport function listRunRecordsForHarnessRoot(harnessRoot: string): HarnessRunRecord[] {\r\n return listRunRecordsAt(harnessRunsDir(harnessRoot));\r\n}\r\n\r\nfunction isRunDirectoryEntry(runDirPath: string): boolean {\r\n try {\r\n return statSync(runDirPath).isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction listRunRecordsAt(runsDir: string): HarnessRunRecord[] {\r\n if (!existsSync(runsDir)) return [];\r\n const runs: HarnessRunRecord[] = [];\r\n for (const entry of readdirSync(runsDir, { withFileTypes: true })) {\r\n if (entry.name === \"runs\") continue;\r\n const runDir = path.join(runsDir, entry.name);\r\n if (!isRunDirectoryEntry(runDir)) continue;\r\n const run = readJson<HarnessRunRecord | undefined>(\r\n path.join(runDir, \"run.json\"),\r\n undefined,\r\n );\r\n if (run?.id) runs.push(run);\r\n }\r\n return runs;\r\n}\r\n\r\nexport function loadWorker(runId: string, name: string): HarnessWorkerRecord {\r\n const { runsDir } = getPaths();\r\n return readJson<HarnessWorkerRecord>(\r\n path.join(runDirPath(runsDir, safeSlug(runId)), \"workers\", safeSlug(name), \"worker.json\"),\r\n );\r\n}\r\n\r\nexport function saveRun(run: HarnessRunRecord): void {\r\n const { runsDir } = getPaths();\r\n writeJson(path.join(runDirPath(runsDir, run.id), \"run.json\"), run);\r\n}\r\n\r\nexport function saveWorker(runId: string, worker: HarnessWorkerRecord): void {\r\n const { runsDir } = getPaths();\r\n writeJson(path.join(runDirPath(runsDir, runId), \"workers\", worker.name, \"worker.json\"), worker);\r\n}\r\n\r\nexport function runDirectory(id: string): string {\r\n const { harnessRoot } = getPaths();\r\n return runDirectoryAt(harnessRoot, id);\r\n}\r\n\r\nexport function runDirectoryAt(harnessRoot: string, id: string): string {\r\n return runDirPath(harnessRunsDir(harnessRoot), safeSlug(id));\r\n}\r\n", "import { existsSync, readdirSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { runDirectory, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\n/**\r\n * Union of `run.json` worker keys and on-disk worker dirs for one run.\r\n *\r\n * Watchdog replenishment can spawn workers whose `worker.json` exists before\r\n * `run.json` is updated (or when concurrent spawns lose a last-write-wins race).\r\n * Finalization, capacity gates, and operator rollups must not treat those\r\n * live workers as absent.\r\n */\r\nexport function listRunWorkerNames(run: HarnessRunRecord): string[] {\r\n const names = new Set<string>();\r\n for (const name of Object.keys(run.workers || {})) {\r\n names.add(safeSlug(name));\r\n }\r\n const workersDir = path.join(runDirectory(run.id), \"workers\");\r\n if (!existsSync(workersDir)) return [...names];\r\n for (const entry of readdirSync(workersDir, { withFileTypes: true })) {\r\n if (!entry.isDirectory()) continue;\r\n names.add(safeSlug(entry.name));\r\n }\r\n return [...names];\r\n}\r\n", "// Resolve structured harness finalResult from a terminal heartbeat line.\r\n\r\nfunction tryParseJsonObject(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed.startsWith(\"{\")) return null;\r\n try {\r\n const parsed: unknown = JSON.parse(trimmed);\r\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction embeddedRecordFromProse(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed) return null;\r\n const direct = tryParseJsonObject(trimmed);\r\n if (direct) return direct;\r\n\r\n const candidates: Record<string, unknown>[] = [];\r\n const fenceRe = /```(?:json)?\\s*([\\s\\S]*?)```/gi;\r\n let fenceMatch: RegExpExecArray | null;\r\n while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {\r\n const fromFence = tryParseJsonObject(fenceMatch[1] ?? \"\");\r\n if (fromFence) candidates.push(fromFence);\r\n }\r\n\r\n const firstBrace = trimmed.indexOf(\"{\");\r\n const lastBrace = trimmed.lastIndexOf(\"}\");\r\n if (firstBrace >= 0 && lastBrace > firstBrace) {\r\n const slice = tryParseJsonObject(trimmed.slice(firstBrace, lastBrace + 1));\r\n if (slice) candidates.push(slice);\r\n }\r\n\r\n return candidates.length > 0 ? candidates[candidates.length - 1]! : null;\r\n}\r\n\r\n/**\r\n * Prefer an explicit heartbeat `finalResult`, else structured JSON embedded in\r\n * `summary`, else the summary string (legacy contract).\r\n */\r\nexport function terminalFinalResultFromHeartbeatRow(\r\n row: Record<string, unknown>,\r\n): unknown {\r\n const explicit = row.finalResult ?? row.final_result;\r\n if (explicit !== undefined && explicit !== null) {\r\n if (typeof explicit === \"string\") {\r\n const embedded = embeddedRecordFromProse(explicit);\r\n return embedded ?? (explicit.trim() || null);\r\n }\r\n return explicit;\r\n }\r\n\r\n const summary = typeof row.summary === \"string\" ? row.summary.trim() : \"\";\r\n if (!summary) return null;\r\n\r\n const embedded = embeddedRecordFromProse(summary);\r\n if (embedded) return embedded;\r\n\r\n return summary;\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport { terminalFinalResultFromHeartbeatRow } from \"./heartbeat-final-result.js\";\r\nimport { safeJson } from \"./util.js\";\r\nimport type { RuntimeBoxResourceSnapshot, RuntimeBoxResourceSnapshotPrEvidence } from \"./box-resource-snapshot.js\";\r\n\r\nexport interface ParsedHeartbeat {\r\n heartbeatCount: number;\r\n lastHeartbeatAt: string | null;\r\n lastHeartbeatPhase: string | null;\r\n lastHeartbeatSummary: string | null;\r\n /** Structured finalResult from the terminal `phase: complete` heartbeat line. */\r\n terminalFinalResult: unknown;\r\n heartbeatBlocker: string | null;\r\n timestampAnomalies: ParsedHeartbeatTimestampAnomaly[];\r\n lastBoxResourceSnapshot: RuntimeBoxResourceSnapshot | null;\r\n lastPrEvidence: RuntimeBoxResourceSnapshotPrEvidence[];\r\n}\r\n\r\nexport interface ParsedHeartbeatTimestampAnomaly {\r\n kind: \"future_heartbeat_timestamp\";\r\n observedAt: string;\r\n clampedTo: string;\r\n}\r\n\r\nconst HEARTBEAT_FUTURE_SKEW_MS = 60_000;\r\n\r\n/** Worker contract: append `phase: \"complete\"` when productively finished. */\r\nexport function isTerminalHeartbeatPhase(phase: string | null | undefined): boolean {\r\n return phase === \"complete\";\r\n}\r\n\r\n/**\r\n * When stdout has no stream-json `result` yet (common for Cursor workers mid-exit),\r\n * treat the worker's completion heartbeat as a synthetic final result so lifecycle\r\n * sync, completion replay, and resource gates advance.\r\n */\r\nexport function terminalFinalResultFromHeartbeat(heartbeat: ParsedHeartbeat): unknown {\r\n if (!isTerminalHeartbeatPhase(heartbeat.lastHeartbeatPhase)) return null;\r\n if (heartbeat.terminalFinalResult !== undefined && heartbeat.terminalFinalResult !== null) {\r\n return heartbeat.terminalFinalResult;\r\n }\r\n const summary = heartbeat.lastHeartbeatSummary?.trim();\r\n return summary || \"completed\";\r\n}\r\n\r\nexport function parseHeartbeat(file: string): ParsedHeartbeat {\r\n const result: ParsedHeartbeat = {\r\n heartbeatCount: 0,\r\n lastHeartbeatAt: null,\r\n lastHeartbeatPhase: null,\r\n lastHeartbeatSummary: null,\r\n terminalFinalResult: null,\r\n heartbeatBlocker: null,\r\n timestampAnomalies: [],\r\n lastBoxResourceSnapshot: null,\r\n lastPrEvidence: [],\r\n };\r\n if (!existsSync(file)) return result;\r\n const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;\r\n const clampedTo = new Date(maxFutureMs).toISOString();\r\n const lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\r\n for (const line of lines) {\r\n const entry = safeJson(line);\r\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) continue;\r\n const row = entry as Record<string, unknown>;\r\n result.heartbeatCount++;\r\n if (row.ts) {\r\n const ts = String(row.ts);\r\n const tsMs = Date.parse(ts);\r\n if (Number.isFinite(tsMs) && tsMs > maxFutureMs) {\r\n result.timestampAnomalies.push({\r\n kind: \"future_heartbeat_timestamp\",\r\n observedAt: ts,\r\n clampedTo,\r\n });\r\n } else {\r\n result.lastHeartbeatAt = ts;\r\n }\r\n }\r\n if (row.phase !== undefined && row.phase !== null) result.lastHeartbeatPhase = String(row.phase);\r\n if (row.summary !== undefined && row.summary !== null) result.lastHeartbeatSummary = String(row.summary);\r\n if (isTerminalHeartbeatPhase(result.lastHeartbeatPhase)) {\r\n result.terminalFinalResult = terminalFinalResultFromHeartbeatRow(row);\r\n }\r\n result.heartbeatBlocker = row.blocker ? String(row.blocker) : null;\r\n if (row.boxResourceSnapshot && typeof row.boxResourceSnapshot === \"object\" && !Array.isArray(row.boxResourceSnapshot)) {\r\n result.lastBoxResourceSnapshot = row.boxResourceSnapshot as RuntimeBoxResourceSnapshot;\r\n }\r\n if (Array.isArray(row.prEvidence)) {\r\n result.lastPrEvidence = row.prEvidence.filter(\r\n (entry): entry is RuntimeBoxResourceSnapshotPrEvidence =>\r\n !!entry &&\r\n typeof entry === \"object\" &&\r\n typeof (entry as RuntimeBoxResourceSnapshotPrEvidence).prUrl === \"string\",\r\n );\r\n }\r\n }\r\n return result;\r\n}\r\n", "/**\r\n * Normalize and classify repo text-search commands for harness operators and chat agents.\r\n *\r\n * Codex/OpenClaw often emit `search \"pattern\" in <scope>` meta that maps poorly to ripgrep\r\n * (e.g. `in !node_modules` instead of `-g '!node_modules/**'`, or `in package.json` as a path).\r\n */\r\n\r\nconst RG_BINARIES = new Set([\"rg\", \"ripgrep\", \"grep\"]);\r\nconst RG_OPTS_WITH_VALUE = new Set([\r\n \"-e\",\r\n \"--regexp\",\r\n \"-f\",\r\n \"--file\",\r\n \"-m\",\r\n \"--max-count\",\r\n \"-A\",\r\n \"--after-context\",\r\n \"-B\",\r\n \"--before-context\",\r\n \"-C\",\r\n \"--context\",\r\n \"-g\",\r\n \"--glob\",\r\n \"--iglob\",\r\n]);\r\n\r\nexport type RepoSearchKind =\r\n | \"not_repo_search\"\r\n | \"bad_scope\"\r\n | \"rg_exclude_syntax\"\r\n | \"no_matches\";\r\n\r\nexport interface RepoSearchContext {\r\n kind: RepoSearchKind;\r\n pattern?: string;\r\n target?: string;\r\n}\r\n\r\nfunction binaryName(token: string | undefined): string | null {\r\n if (!token) return null;\r\n const base = token.split(\"/\").pop() ?? token;\r\n return base.replace(/\\.exe$/i, \"\").toLowerCase();\r\n}\r\n\r\nfunction splitShellWords(input: string): string[] {\r\n if (!input) return [];\r\n const words: string[] = [];\r\n let current = \"\";\r\n let quote: string | undefined;\r\n let escaped = false;\r\n for (const char of input) {\r\n if (escaped) {\r\n current += char;\r\n escaped = false;\r\n continue;\r\n }\r\n if (char === \"\\\\\") {\r\n escaped = true;\r\n continue;\r\n }\r\n if (quote) {\r\n if (char === quote) quote = undefined;\r\n else current += char;\r\n continue;\r\n }\r\n if (char === '\"' || char === \"'\") {\r\n quote = char;\r\n continue;\r\n }\r\n if (/\\s/.test(char)) {\r\n if (current) {\r\n words.push(current);\r\n current = \"\";\r\n }\r\n continue;\r\n }\r\n current += char;\r\n }\r\n if (current) words.push(current);\r\n return words;\r\n}\r\n\r\nfunction isRgArgv(argv: string[]): boolean {\r\n const bin = binaryName(argv[0]);\r\n return Boolean(bin && RG_BINARIES.has(bin));\r\n}\r\n\r\nexport function isSingleFileSearchTarget(target: string | undefined): boolean {\r\n if (!target || target.includes(\"/\") || target.includes(\"*\")) return false;\r\n return /\\.(?:json|md|mjs|cjs|js|ts|tsx|yaml|yml)$/iu.test(target);\r\n}\r\n\r\n/** `!node_modules` as a path is invalid \u2014 ripgrep needs `-g '!node_modules/**'`. */\r\nexport function isRgExcludeScopeTarget(target: string | undefined): boolean {\r\n if (!target) return false;\r\n const t = target.trim();\r\n return t.startsWith(\"!\") && !t.includes(\"/\") && !t.endsWith(\"/**\");\r\n}\r\n\r\nfunction fixRgGlobToken(token: string): string {\r\n if (!token.startsWith(\"--glob=\")) return token;\r\n const value = token.slice(\"--glob=\".length);\r\n if (value.startsWith(\"!\") && !value.includes(\"/\") && !value.endsWith(\"/**\")) {\r\n return `--glob=${value}/**`;\r\n }\r\n return token;\r\n}\r\n\r\nfunction collectRgPositional(argv: string[]): string[] {\r\n const positional: string[] = [];\r\n for (let i = 1; i < argv.length; i += 1) {\r\n const token = argv[i];\r\n if (!token) continue;\r\n if (token === \"--\") {\r\n positional.push(...argv.slice(i + 1));\r\n break;\r\n }\r\n if (token.startsWith(\"-\")) {\r\n if (token.includes(\"=\")) continue;\r\n if (RG_OPTS_WITH_VALUE.has(token)) i += 1;\r\n continue;\r\n }\r\n positional.push(token);\r\n }\r\n return positional;\r\n}\r\n\r\nexport function normalizeRgArgv(argv: string[]): { argv: string[]; changed: boolean } {\r\n let changed = false;\r\n const out = argv.map((token) => {\r\n const fixed = fixRgGlobToken(token);\r\n if (fixed !== token) changed = true;\r\n return fixed;\r\n });\r\n const positional = collectRgPositional(out);\r\n if (positional.length === 2) {\r\n const [pattern, target] = positional;\r\n if (isSingleFileSearchTarget(target)) {\r\n return { argv: [out[0] ?? \"rg\", \"-g\", target, pattern, \".\"], changed: true };\r\n }\r\n }\r\n return { argv: out, changed };\r\n}\r\n\r\nexport function normalizeRepoSearchCommand(command: string): { command: string; changed: boolean } {\r\n const trimmed = command.trim();\r\n if (!trimmed) return { command: trimmed, changed: false };\r\n const joiner = trimmed.includes(\"&&\") ? \" && \" : trimmed.includes(\"||\") ? \" || \" : \"; \";\r\n const stages = trimmed.split(/\\s*(?:&&|\\|\\||;)\\s*/u);\r\n let changed = false;\r\n const normalizedStages = stages.map((stage) => {\r\n const argv = splitShellWords(stage.trim());\r\n if (!argv.length || !isRgArgv(argv)) return stage;\r\n const normalized = normalizeRgArgv(argv);\r\n if (normalized.changed) {\r\n changed = true;\r\n return normalized.argv.join(\" \");\r\n }\r\n return stage;\r\n });\r\n if (!changed) return { command: trimmed, changed: false };\r\n return { command: normalizedStages.join(joiner), changed: true };\r\n}\r\n\r\nexport function extractSearchMeta(meta: string): { pattern?: string; target?: string } {\r\n if (!meta) return {};\r\n const pipelineMatch = meta.match(/search\\s+\"(.+)\"\\s+in\\s+([^()]+?)(?:\\s*\\(|$)/iu);\r\n if (pipelineMatch) {\r\n return { pattern: pipelineMatch[1], target: pipelineMatch[2]?.trim() };\r\n }\r\n const match = meta.match(/^search\\s+\"(.+)\"\\s+in\\s+(.+)$/iu);\r\n if (!match) return {};\r\n return { pattern: match[1], target: match[2]?.trim() };\r\n}\r\n\r\nexport function classifyRepoSearchMeta(meta: string): RepoSearchContext {\r\n const { pattern, target } = extractSearchMeta(meta);\r\n if (!pattern) return { kind: \"not_repo_search\" };\r\n if (isRgExcludeScopeTarget(target)) {\r\n return { kind: \"rg_exclude_syntax\", pattern, target };\r\n }\r\n if (isSingleFileSearchTarget(target)) {\r\n return { kind: \"bad_scope\", pattern, target };\r\n }\r\n return { kind: \"not_repo_search\", pattern, target };\r\n}\r\n\r\nexport function metaToNormalizedRgCommand(meta: string): { command: string; changed: boolean } | null {\r\n const { pattern, target } = extractSearchMeta(meta);\r\n if (!pattern) return null;\r\n if (isRgExcludeScopeTarget(target)) {\r\n const glob = `${target!.trim()}/**`;\r\n return {\r\n command: `rg \"${pattern}\" -g '${glob}' .`,\r\n changed: true,\r\n };\r\n }\r\n if (target && isSingleFileSearchTarget(target)) {\r\n return {\r\n command: `rg -g ${target} \"${pattern}\" .`,\r\n changed: true,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nexport function formatRepoSearchGuidance(ctx: RepoSearchContext): string | null {\r\n if (\r\n ctx.kind === \"bad_scope\" &&\r\n ctx.pattern?.includes(\"agent-os-land-pr\") &&\r\n ctx.target === \"package.json\"\r\n ) {\r\n return (\r\n \"Search package.json with a glob from the repo root: \" +\r\n \"`rg -g package.json agent-os-land-pr .` \u2014 or run `node scripts/agent-os-land-pr.mjs <pr-url>` directly.\"\r\n );\r\n }\r\n if (ctx.kind === \"bad_scope\" && ctx.pattern && ctx.target) {\r\n return `Use \\`rg -g '${ctx.target}' ${ctx.pattern} .\\` from the repo root instead of treating ${ctx.target} as a folder.`;\r\n }\r\n if (ctx.kind === \"rg_exclude_syntax\" && ctx.pattern) {\r\n const glob = ctx.target ? `${ctx.target.trim()}/**` : \"!node_modules/**\";\r\n return (\r\n `Repo search scope \\`${ctx.target ?? \"!node_modules\"}\\` is not a valid ripgrep path. ` +\r\n `Use \\`rg \"${ctx.pattern}\" -g '${glob}' .\\` from the repo root (exclude globs need a \\`/**\\` suffix).`\r\n );\r\n }\r\n if (ctx.kind === \"no_matches\" && ctx.pattern) {\r\n return `No matches for \"${ctx.pattern}\". Try a broader pattern, drop overly short tokens, or search from the repo root with \\`rg \"${ctx.pattern}\" .\\`.`;\r\n }\r\n return null;\r\n}\r\n\r\n/** Extract `search \"\u2026\" in \u2026` from a tool-failure line or command string. */\r\nexport function extractSearchMetaFromToolLine(line: string): string | null {\r\n const match = line.match(/search\\s+\"(.+)\"\\s+in\\s+([^()]+?)(?:\\s*\\(agent\\)|\\s*failed|$)/iu);\r\n if (!match) return null;\r\n return `search \"${match[1]}\" in ${match[2]?.trim()}`;\r\n}\r\n\r\nexport function diagnoseRepoSearchFailure(input: {\r\n meta?: string;\r\n command?: string;\r\n exitCode?: number;\r\n}): string | null {\r\n const meta =\r\n input.meta?.trim() ||\r\n (input.command ? extractSearchMetaFromToolLine(input.command) : null) ||\r\n null;\r\n if (meta) {\r\n const ctx = classifyRepoSearchMeta(meta);\r\n const guidance = formatRepoSearchGuidance(ctx);\r\n if (guidance) return guidance;\r\n const normalized = metaToNormalizedRgCommand(meta);\r\n if (normalized?.changed) {\r\n return `Repo search used an invalid scope. Retry with: \\`${normalized.command}\\`.`;\r\n }\r\n }\r\n if (input.command && /\\b(rg|ripgrep)\\b/i.test(input.command)) {\r\n const normalized = normalizeRepoSearchCommand(input.command);\r\n if (normalized.changed) {\r\n return `Ripgrep scope may be invalid. Retry with: \\`${normalized.command}\\`.`;\r\n }\r\n if (input.exitCode === 1) {\r\n return \"Ripgrep returned no matches (exit 1). Try a broader pattern or search from the repo root.\";\r\n }\r\n }\r\n return null;\r\n}\r\n", "// Classify harness shell tool results for operator-facing streams (tail, status, Telegram).\r\n//\r\n// npm audit exits 1 when advisories exist \u2014 that is a successful run with findings,\r\n// not a command execution failure. ripgrep exits 1 when there are no matches \u2014 also\r\n// not a command execution failure. Reserve \"command failed\" for ENOLOCK, network\r\n// errors, invalid JSON, and other tool failures.\r\n\r\nimport { diagnoseRepoSearchFailure, normalizeRepoSearchCommand } from \"./repo-search.js\";\r\n\r\nexport type ShellCommandOutcomeKind =\r\n | \"success\"\r\n | \"audit_findings\"\r\n | \"search_no_matches\"\r\n | \"command_failure\";\r\n\r\nexport interface NpmAuditSummary {\r\n total: number;\r\n critical: number;\r\n high: number;\r\n moderate: number;\r\n low: number;\r\n info: number;\r\n}\r\n\r\nexport interface ShellCommandOutcome {\r\n kind: ShellCommandOutcomeKind;\r\n exitCode: number;\r\n /** Short operator-facing line (no raw JSON blob). */\r\n summary: string;\r\n /** Present when kind === audit_findings and JSON parsed. */\r\n audit?: NpmAuditSummary;\r\n /** When JSON was expected but invalid. */\r\n parseError?: string;\r\n}\r\n\r\nconst NPM_AUDIT_RE = /\\bnpm\\s+audit\\b/i;\r\nconst RG_CMD_RE = /\\b(rg|ripgrep)\\b/i;\r\nconst RG_REAL_ERROR_RE = /\\b(error|invalid|unknown|panic|not found)\\b/i;\r\n\r\nfunction tidy(text: string, max = 200): string {\r\n const one = text.replace(/\\s+/g, \" \").trim();\r\n return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;\r\n}\r\n\r\nfunction extractJsonObject(text: string): unknown | null {\r\n const trimmed = text.trim();\r\n if (!trimmed) return null;\r\n if (trimmed.startsWith(\"{\")) {\r\n try {\r\n return JSON.parse(trimmed);\r\n } catch {\r\n /* fall through \u2014 scan for embedded object */\r\n }\r\n }\r\n const start = trimmed.indexOf(\"{\");\r\n const end = trimmed.lastIndexOf(\"}\");\r\n if (start >= 0 && end > start) {\r\n try {\r\n return JSON.parse(trimmed.slice(start, end + 1));\r\n } catch {\r\n return null;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\r\n}\r\n\r\nexport function summarizeNpmAuditReport(report: Record<string, unknown>): NpmAuditSummary | null {\r\n const meta = report.metadata;\r\n if (!isRecord(meta)) return null;\r\n const vuln = meta.vulnerabilities;\r\n if (!isRecord(vuln)) return null;\r\n const num = (key: string) => (typeof vuln[key] === \"number\" ? vuln[key] : 0);\r\n const summary: NpmAuditSummary = {\r\n info: num(\"info\"),\r\n low: num(\"low\"),\r\n moderate: num(\"moderate\"),\r\n high: num(\"high\"),\r\n critical: num(\"critical\"),\r\n total: num(\"total\"),\r\n };\r\n if (\r\n typeof vuln.total !== \"number\" &&\r\n !summary.critical &&\r\n !summary.high &&\r\n !summary.moderate &&\r\n !summary.low &&\r\n !summary.info\r\n ) {\r\n return null;\r\n }\r\n return summary;\r\n}\r\n\r\nfunction formatAuditSummaryLine(audit: NpmAuditSummary): string {\r\n const parts: string[] = [];\r\n if (audit.critical) parts.push(`${audit.critical} critical`);\r\n if (audit.high) parts.push(`${audit.high} high`);\r\n if (audit.moderate) parts.push(`${audit.moderate} moderate`);\r\n if (audit.low) parts.push(`${audit.low} low`);\r\n if (audit.info) parts.push(`${audit.info} info`);\r\n const breakdown = parts.length ? parts.join(\", \") : \"see report\";\r\n return `npm audit: ${audit.total} vulnerabilit${audit.total === 1 ? \"y\" : \"ies\"} (${breakdown}) \u2014 remediation required`;\r\n}\r\n\r\nfunction npmAuditFailureReason(report: Record<string, unknown>, stderr: string): string {\r\n const err = report.error;\r\n if (isRecord(err)) {\r\n const summary = typeof err.summary === \"string\" ? err.summary.trim() : \"\";\r\n const code = typeof err.code === \"string\" ? err.code.trim() : \"\";\r\n if (summary) return code ? `${code}: ${summary}` : summary;\r\n if (code) return code;\r\n }\r\n const detail = typeof report.message === \"string\" ? report.message.trim() : \"\";\r\n if (detail) return detail;\r\n const errTail = stderr.trim();\r\n if (errTail) return tidy(errTail.split(\"\\n\").find(Boolean) ?? errTail, 160);\r\n return \"npm audit failed\";\r\n}\r\n\r\nexport function classifyNpmAuditOutcome(input: {\r\n exitCode: number;\r\n stdout: string;\r\n stderr: string;\r\n}): ShellCommandOutcome {\r\n const combined = `${input.stdout}\\n${input.stderr}`.trim();\r\n const parsed = extractJsonObject(combined);\r\n\r\n if (!parsed || !isRecord(parsed)) {\r\n const tail = tidy(combined || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `npm audit failed (invalid or missing JSON): ${tail}`,\r\n parseError: \"invalid_json\",\r\n };\r\n }\r\n\r\n if (isRecord(parsed.error)) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `npm audit command failed: ${npmAuditFailureReason(parsed, input.stderr)}`,\r\n };\r\n }\r\n\r\n const audit = summarizeNpmAuditReport(parsed);\r\n if (!audit) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: \"npm audit failed: JSON response missing vulnerability metadata\",\r\n parseError: \"missing_metadata\",\r\n };\r\n }\r\n\r\n if (input.exitCode === 0 && audit.total === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: \"npm audit: no vulnerabilities reported\",\r\n audit,\r\n };\r\n }\r\n\r\n return {\r\n kind: \"audit_findings\",\r\n exitCode: input.exitCode,\r\n summary: formatAuditSummaryLine(audit),\r\n audit,\r\n };\r\n}\r\n\r\nfunction isNpmAuditCommand(command: string): boolean {\r\n return NPM_AUDIT_RE.test(command);\r\n}\r\n\r\nfunction isRgCommand(command: string): boolean {\r\n return RG_CMD_RE.test(command);\r\n}\r\n\r\nfunction classifyRgOutcome(input: {\r\n command: string;\r\n exitCode: number;\r\n stdout: string;\r\n stderr: string;\r\n interleaved: string;\r\n}): ShellCommandOutcome {\r\n const diagnosis = diagnoseRepoSearchFailure({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n });\r\n\r\n if (input.exitCode === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: \"ripgrep finished (exit 0)\",\r\n };\r\n }\r\n\r\n if (input.exitCode === 1) {\r\n const errText = (input.stderr || input.interleaved).trim();\r\n if (errText && RG_REAL_ERROR_RE.test(errText)) {\r\n const tail = tidy(errText, 160);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: 1,\r\n summary: diagnosis ?? `ripgrep failed (exit 1): ${tail}`,\r\n };\r\n }\r\n const normalized = normalizeRepoSearchCommand(input.command);\r\n const retry =\r\n normalized.changed && !diagnosis ? ` Retry with: \\`${normalized.command}\\`.` : \"\";\r\n return {\r\n kind: \"search_no_matches\",\r\n exitCode: 1,\r\n summary:\r\n diagnosis ??\r\n `ripgrep: no matches (exit 1).${retry} Try a broader pattern or search from the repo root.`,\r\n };\r\n }\r\n\r\n const tail = tidy(input.interleaved || input.stdout || input.stderr || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: diagnosis ?? `ripgrep failed (exit ${input.exitCode}): ${tail}`,\r\n };\r\n}\r\n\r\nexport function classifyShellCommandOutcome(input: {\r\n command: string;\r\n exitCode: number;\r\n stdout?: string;\r\n stderr?: string;\r\n interleavedOutput?: string;\r\n}): ShellCommandOutcome {\r\n const stdout = input.stdout ?? \"\";\r\n const stderr = input.stderr ?? \"\";\r\n const interleaved = input.interleavedOutput ?? \"\";\r\n\r\n if (isNpmAuditCommand(input.command)) {\r\n const body = stdout.trim() || interleaved.trim() || stderr.trim();\r\n return classifyNpmAuditOutcome({\r\n exitCode: input.exitCode,\r\n stdout: body,\r\n stderr,\r\n });\r\n }\r\n\r\n if (isRgCommand(input.command)) {\r\n return classifyRgOutcome({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n stdout,\r\n stderr,\r\n interleaved,\r\n });\r\n }\r\n\r\n const searchDiagnosis = diagnoseRepoSearchFailure({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n });\r\n if (searchDiagnosis && input.exitCode !== 0) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: searchDiagnosis,\r\n };\r\n }\r\n\r\n if (input.exitCode === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: `command succeeded (exit 0)`,\r\n };\r\n }\r\n\r\n const tail = tidy(interleaved || stdout || stderr || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `command failed (exit ${input.exitCode}): ${tail}`,\r\n };\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport {\r\n classifyShellCommandOutcome,\r\n type ShellCommandOutcome,\r\n} from \"./shell-command-outcome.js\";\r\nimport { oneLine, safeJson } from \"./util.js\";\r\n\r\nexport interface ParsedStream {\r\n firstEventAt: string | null;\r\n lastEventAt: string | null;\r\n currentTool: string | null;\r\n finalResult: unknown;\r\n error: string | null;\r\n /** Most recent non-success shell outcome for operator error streams. */\r\n lastShellOutcome: ShellCommandOutcome | null;\r\n}\r\n\r\nfunction eventTimestampIso(event: Record<string, unknown>): string | undefined {\r\n const tsMs = event.timestamp_ms as number | undefined;\r\n return (event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : undefined)) as\r\n | string\r\n | undefined;\r\n}\r\n\r\n/** Cursor `stream-json` encodes tools as `{ grepToolCall: \u2026 }` keys on `tool_call`. */\r\nfunction cursorToolNameFromCall(toolCall: Record<string, unknown> | undefined): string | null {\r\n if (!toolCall) return null;\r\n for (const key of Object.keys(toolCall)) {\r\n if (key.endsWith(\"ToolCall\")) {\r\n const stem = key.slice(0, -\"ToolCall\".length);\r\n return stem.length ? stem : key;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction recordStreamResult(result: ParsedStream, event: Record<string, unknown>): void {\r\n result.finalResult = event.result || event.subtype || event.terminal_reason || \"completed\";\r\n if (event.is_error) {\r\n result.error = String(event.result || event.api_error_status || \"stream result error\");\r\n }\r\n}\r\n\r\nfunction shellPayloadFromCursorEvent(\r\n event: Record<string, unknown>,\r\n): { command: string; exitCode: number; stdout: string; stderr: string; interleaved: string } | null {\r\n if (event.type !== \"tool_call\" || event.subtype !== \"completed\") return null;\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : null;\r\n const shell = toolCall?.shellToolCall;\r\n if (!shell || typeof shell !== \"object\" || Array.isArray(shell)) return null;\r\n const shellObj = shell as Record<string, unknown>;\r\n const args = shellObj.args;\r\n const command =\r\n args && typeof args === \"object\" && !Array.isArray(args) && typeof (args as Record<string, unknown>).command === \"string\"\r\n ? String((args as Record<string, unknown>).command)\r\n : \"\";\r\n const result = shellObj.result;\r\n if (!result || typeof result !== \"object\" || Array.isArray(result)) return null;\r\n const body = (result as Record<string, unknown>).success ?? (result as Record<string, unknown>).failure;\r\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return null;\r\n const row = body as Record<string, unknown>;\r\n const exitCode = typeof row.exitCode === \"number\" ? row.exitCode : 0;\r\n return {\r\n command,\r\n exitCode,\r\n stdout: typeof row.stdout === \"string\" ? row.stdout : \"\",\r\n stderr: typeof row.stderr === \"string\" ? row.stderr : \"\",\r\n interleaved: typeof row.interleavedOutput === \"string\" ? row.interleavedOutput : \"\",\r\n };\r\n}\r\n\r\nfunction applyShellOutcome(parsed: ParsedStream, outcome: ShellCommandOutcome): void {\r\n if (outcome.kind === \"success\" || outcome.kind === \"search_no_matches\") return;\r\n parsed.lastShellOutcome = outcome;\r\n}\r\n\r\n/**\r\n * Parse harness worker stdout (`stream-json` from Claude Code or Cursor Agent).\r\n * Cursor emits `tool_call` events and may only write `type: \"result\"` after exit;\r\n * completion heartbeats are merged in `computeWorkerStatus`.\r\n */\r\nexport function parseHarnessStream(file: string): ParsedStream {\r\n const result: ParsedStream = {\r\n firstEventAt: null,\r\n lastEventAt: null,\r\n currentTool: null,\r\n finalResult: null,\r\n error: null,\r\n lastShellOutcome: null,\r\n };\r\n if (!existsSync(file)) return result;\r\n const lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\r\n for (const line of lines) {\r\n const event = safeJson(line) as Record<string, unknown> | null;\r\n if (!event) continue;\r\n const ts = eventTimestampIso(event);\r\n if (ts) {\r\n result.firstEventAt ||= ts;\r\n result.lastEventAt = ts;\r\n }\r\n if (\r\n event.type === \"stream_event\" &&\r\n event.event &&\r\n typeof event.event === \"object\" &&\r\n (event.event as Record<string, unknown>).type === \"content_block_start\"\r\n ) {\r\n const block = (event.event as Record<string, unknown>).content_block as Record<string, unknown> | undefined;\r\n if (block?.type === \"tool_use\") result.currentTool = String(block.name || \"tool\");\r\n }\r\n if (event.type === \"assistant\" && event.message && typeof event.message === \"object\") {\r\n const content = (event.message as Record<string, unknown>).content;\r\n if (Array.isArray(content)) {\r\n const tool = content.find((item) => item?.type === \"tool_use\") as Record<string, unknown> | undefined;\r\n if (tool) result.currentTool = String(tool.name || result.currentTool);\r\n }\r\n }\r\n if (event.type === \"tool_call\" && event.subtype === \"started\") {\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : undefined;\r\n const name = cursorToolNameFromCall(toolCall);\r\n if (name) result.currentTool = name;\r\n }\r\n const shell = shellPayloadFromCursorEvent(event);\r\n if (shell) {\r\n applyShellOutcome(\r\n result,\r\n classifyShellCommandOutcome({\r\n command: shell.command,\r\n exitCode: shell.exitCode,\r\n stdout: shell.stdout,\r\n stderr: shell.stderr,\r\n interleavedOutput: shell.interleaved,\r\n }),\r\n );\r\n }\r\n if (event.type === \"result\") {\r\n recordStreamResult(result, event);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/** @deprecated Use {@link parseHarnessStream} \u2014 kept for existing imports. */\r\nexport function parseClaudeStream(file: string): ParsedStream {\r\n return parseHarnessStream(file);\r\n}\r\n\r\nexport function summarizeShellToolCallEvent(event: Record<string, unknown>): string | undefined {\r\n const shell = shellPayloadFromCursorEvent(event);\r\n if (!shell) return undefined;\r\n const outcome = classifyShellCommandOutcome({\r\n command: shell.command,\r\n exitCode: shell.exitCode,\r\n stdout: shell.stdout,\r\n stderr: shell.stderr,\r\n interleavedOutput: shell.interleaved,\r\n });\r\n const cmd = oneLine(shell.command).slice(0, 120);\r\n if (outcome.kind === \"audit_findings\") {\r\n return `[audit:findings] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n if (outcome.kind === \"search_no_matches\") {\r\n return `[search:no_matches] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n if (outcome.kind === \"command_failure\") {\r\n return `[command:failed] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n return `[command:ok] exit 0${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n}\r\n\r\nexport function summarizeEvent(event: Record<string, unknown>): string | undefined {\r\n if (event.type === \"system\" && event.subtype) {\r\n return `[system:${event.subtype}] ${String(event.status || event.cwd || \"\")}`.trim();\r\n }\r\n if (event.type === \"stream_event\" && event.event && typeof event.event === \"object\") {\r\n const type = (event.event as Record<string, unknown>).type;\r\n if (type === \"content_block_start\") {\r\n const block = (event.event as Record<string, unknown>).content_block as Record<string, unknown> | undefined;\r\n if (block?.type === \"tool_use\") return `[tool:start] ${block.name}`;\r\n }\r\n if (type === \"content_block_delta\") {\r\n const delta = (event.event as Record<string, unknown>).delta as Record<string, unknown> | undefined;\r\n if (delta?.partial_json) return `[tool:input] ${delta.partial_json}`;\r\n }\r\n if (type === \"message_stop\") return \"[message:stop]\";\r\n return type ? `[stream:${type}]` : undefined;\r\n }\r\n if (event.type === \"assistant\" && event.message && typeof event.message === \"object\") {\r\n const content = (event.message as Record<string, unknown>).content;\r\n if (Array.isArray(content)) {\r\n const text = content.find((item) => item?.type === \"text\") as Record<string, unknown> | undefined;\r\n if (text) return `[assistant] ${oneLine(String(text.text || \"\"))}`;\r\n const tool = content.find((item) => item?.type === \"tool_use\") as Record<string, unknown> | undefined;\r\n if (tool) return `[tool] ${tool.name} ${JSON.stringify(tool.input || {})}`;\r\n }\r\n }\r\n if (event.type === \"user\" && event.tool_use_result) {\r\n const result = event.tool_use_result as Record<string, unknown>;\r\n return `[tool:result] stdout=${JSON.stringify(result.stdout || \"\")} stderr=${JSON.stringify(result.stderr || \"\")}`;\r\n }\r\n if (event.type === \"tool_call\") {\r\n const subtype = String(event.subtype || \"\");\r\n const shellSummary =\r\n subtype === \"completed\" ? summarizeShellToolCallEvent(event) : undefined;\r\n if (shellSummary) return shellSummary;\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : undefined;\r\n const name = cursorToolNameFromCall(toolCall) ?? \"tool\";\r\n return `[tool:${subtype}] ${name}`;\r\n }\r\n if (event.type === \"result\") {\r\n return `[result] ${event.subtype || \"\"} ${oneLine(String(event.result || \"\"))}`.trim();\r\n }\r\n return undefined;\r\n}\r\n", "// Exit normalization for workers that died without a stream-json final result.\r\n//\r\n// When a worker process exits before recording a `result` event, the status path\r\n// used to surface a single generic \"process exited without a final result\"\r\n// needs_attention \u2014 indistinguishable whether the agent crashed mid-task or the\r\n// provider CLI rejected the model/args at startup. That made model/provider\r\n// misconfigurations look like silent stalls the watchdog had to triage by hand.\r\n//\r\n// `classifyExitFailure` inspects the worker's stderr/error tail and, when it\r\n// matches a known startup/config failure (model rejection, missing CLI, auth),\r\n// returns a structured `blocked` classification with a precise reason. The\r\n// status path promotes that to `attention.state = \"blocked\"` \u2014 a real board\r\n// attention state that flows through the harness completion ingest unchanged \u2014\r\n// instead of the catch-all needs_attention.\r\n\r\nexport interface ExitClassification {\r\n /** True when the failure is a structural blocker an operator must fix. */\r\n blocked: boolean;\r\n /** Precise, human-readable reason for the blocker. */\r\n reason: string;\r\n}\r\n\r\ninterface FailurePattern {\r\n test: RegExp;\r\n label: string;\r\n}\r\n\r\n// Ordered most-specific first. Each entry maps a recognizable stderr signature to\r\n// a short blocker label; the matched error tail is appended for context.\r\nconst FAILURE_PATTERNS: FailurePattern[] = [\r\n {\r\n test: /\\b(?:invalid|unknown|unsupported|unrecognized)\\b[^.\\n]*\\bmodel\\b/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /\\bmodel\\b[^.\\n]*\\b(?:not\\s+(?:found|supported|available|recognized|valid)|is\\s+not\\s+valid|does\\s+not\\s+exist)/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /\\b(?:did you mean|available models|choose (?:a|one of)|supported models)\\b/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /model preflight failed/i,\r\n label: \"model/provider preflight failed\",\r\n },\r\n {\r\n test: /\\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\\b/i,\r\n label: \"provider CLI is missing or not on PATH\",\r\n },\r\n {\r\n test: /\\bfailed to spawn\\b/i,\r\n label: \"provider failed to spawn the worker process\",\r\n },\r\n {\r\n test: /\\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\\b/i,\r\n label: \"provider authentication failed\",\r\n },\r\n];\r\n\r\n/** Collapse whitespace and clip a noisy error tail to a single readable line. */\r\nfunction tidy(errorText: string, max = 240): string {\r\n const oneLine = errorText.replace(/\\s+/g, \" \").trim();\r\n return oneLine.length > max ? `${oneLine.slice(0, max - 1)}\u2026` : oneLine;\r\n}\r\n\r\n/**\r\n * Classify a dead worker's error/stderr output. Returns a structured blocker when\r\n * the text matches a known startup/config failure, or null when it does not (the\r\n * caller should fall back to the generic needs_attention path).\r\n */\r\nexport function classifyExitFailure(\r\n errorText: string | null | undefined,\r\n): ExitClassification | null {\r\n const text = (errorText ?? \"\").trim();\r\n if (!text) return null;\r\n for (const pattern of FAILURE_PATTERNS) {\r\n if (pattern.test.test(text)) {\r\n return { blocked: true, reason: `${pattern.label}: ${tidy(text)}` };\r\n }\r\n }\r\n return null;\r\n}\r\n", "// Workers that die without a stream-json `result` event but leave salvageable work\r\n// behind (uncommitted changes and/or commits ahead of the run base). Distinct from\r\n// a generic \"process exited without a final result\" stall \u2014 operators need a\r\n// review-needed signal and a follow-up salvage/landing lane (PR #285 class).\r\n\r\nimport type { GitAncestry } from \"./git.js\";\r\n\r\nexport type ExitedSalvageKind = \"none\" | \"uncommitted\" | \"committed_ahead\" | \"both\";\r\n\r\nexport interface ExitedSalvageAssessment {\r\n kind: ExitedSalvageKind;\r\n /** True when the worktree has reviewable uncommitted and/or committed-ahead work. */\r\n salvageable: boolean;\r\n uncommittedCount: number;\r\n headCommit: string | null;\r\n /** Board / attention reason \u2014 stable prefix for downstream parsers. */\r\n attentionReason: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const trimmed = value.trim();\r\n return trimmed.length ? trimmed : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"boolean\") return value;\r\n if (Array.isArray(value)) return value.length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction committedHeadFromAncestry(ancestry: GitAncestry | null | undefined): string | null {\r\n if (!ancestry?.checked) return null;\r\n if (ancestry.headIsAncestorOfBase !== false) return null;\r\n return trimOrNull(ancestry.head);\r\n}\r\n\r\nfunction buildAttentionReason(\r\n kind: ExitedSalvageKind,\r\n uncommittedCount: number,\r\n headCommit: string | null,\r\n): string {\r\n const parts: string[] = [\"exited_with_changes_salvage\"];\r\n if (kind === \"uncommitted\" || kind === \"both\") {\r\n parts.push(\r\n `${uncommittedCount} uncommitted change${uncommittedCount === 1 ? \"\" : \"s\"} with no final result`,\r\n );\r\n }\r\n if ((kind === \"committed_ahead\" || kind === \"both\") && headCommit) {\r\n const sha = headCommit.length > 12 ? headCommit.slice(0, 12) : headCommit;\r\n parts.push(`commit ${sha} ahead of base with no final result`);\r\n }\r\n parts.push(\"review worktree \u2014 commit, open a PR, or run a salvage worker before discarding\");\r\n return parts.join(\": \");\r\n}\r\n\r\n/**\r\n * Classify a dead worker with no `finalResult`. Returns null when the worker is\r\n * still alive or already recorded a final result.\r\n */\r\nexport function assessExitedWorkerSalvage(input: {\r\n alive: boolean;\r\n finalResult: unknown;\r\n changedFiles?: string[];\r\n gitAncestry?: GitAncestry | null;\r\n headCommit?: string | null;\r\n}): ExitedSalvageAssessment | null {\r\n if (input.alive || hasFinalResult(input.finalResult)) return null;\r\n\r\n const uncommittedCount = (input.changedFiles ?? []).filter((line) => line.trim()).length;\r\n const headCommit = trimOrNull(input.headCommit) ?? committedHeadFromAncestry(input.gitAncestry);\r\n const hasUncommitted = uncommittedCount > 0;\r\n const hasCommittedAhead = Boolean(headCommit);\r\n\r\n if (!hasUncommitted && !hasCommittedAhead) {\r\n return {\r\n kind: \"none\",\r\n salvageable: false,\r\n uncommittedCount: 0,\r\n headCommit: null,\r\n attentionReason: \"process exited without a final result\",\r\n };\r\n }\r\n\r\n const kind: ExitedSalvageKind =\r\n hasUncommitted && hasCommittedAhead ? \"both\" : hasUncommitted ? \"uncommitted\" : \"committed_ahead\";\r\n\r\n return {\r\n kind,\r\n salvageable: true,\r\n uncommittedCount,\r\n headCommit,\r\n attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit),\r\n };\r\n}\r\n", "import type { GitAncestry } from \"./git.js\";\r\n\r\nexport type WorkerLandingBlockReason = \"dirty_worktree_no_pr\";\r\n\r\nexport interface WorkerLandingSnapshot {\r\n finalResult: unknown;\r\n changedFiles: string[];\r\n headCommit?: string | null;\r\n prUrl?: string | null;\r\n artifactBundlePath?: string | null;\r\n patchPath?: string | null;\r\n gitAncestry?: GitAncestry | null;\r\n}\r\n\r\nexport interface WorkerLandingVerdict {\r\n /** When true, do not treat the worker as cleanly landed/done. */\r\n blocked: boolean;\r\n reason?: WorkerLandingBlockReason;\r\n /** Human-readable attention reason for boards and completion payloads. */\r\n detail?: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const trimmed = value.trim();\r\n return trimmed.length ? trimmed : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"boolean\") return value;\r\n if (Array.isArray(value)) return value.length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction hasCommittedLandingRef(snapshot: WorkerLandingSnapshot): boolean {\r\n if (trimOrNull(snapshot.headCommit)) return true;\r\n if (trimOrNull(snapshot.prUrl)) return true;\r\n if (trimOrNull(snapshot.artifactBundlePath)) return true;\r\n if (trimOrNull(snapshot.patchPath)) return true;\r\n const ancestry = snapshot.gitAncestry;\r\n if (ancestry?.checked && ancestry.headIsAncestorOfBase === false && trimOrNull(ancestry.head)) {\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Hard landing gate: a recorded final result is not sufficient when the worker\r\n * left uncommitted code and has no commit/PR/patch/bundle landing path.\r\n */\r\nexport function assessWorkerLanding(snapshot: WorkerLandingSnapshot): WorkerLandingVerdict {\r\n if (!hasFinalResult(snapshot.finalResult)) return { blocked: false };\r\n if (snapshot.changedFiles.length === 0) return { blocked: false };\r\n if (!hasCommittedLandingRef(snapshot)) {\r\n return {\r\n blocked: true,\r\n reason: \"dirty_worktree_no_pr\",\r\n detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s) with no commit or PR; commit, open a PR, or discard before landing`,\r\n };\r\n }\r\n return {\r\n blocked: true,\r\n detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s); commit or discard before landing`,\r\n };\r\n}\r\n\r\nexport function landingAttentionReason(verdict: WorkerLandingVerdict): string | undefined {\r\n if (!verdict.blocked) return undefined;\r\n return verdict.detail ?? verdict.reason ?? \"dirty_worktree_no_pr\";\r\n}\r\n", "// Extract structured harness finalResult JSON embedded in markdown prose.\r\n\r\nfunction tryParseJsonObject(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed.startsWith(\"{\")) return null;\r\n try {\r\n const parsed: unknown = JSON.parse(trimmed);\r\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction reconciliationEntryCount(record: Record<string, unknown>): number {\r\n const raw =\r\n record.targetPrReconciliation ??\r\n record.target_pr_reconciliation ??\r\n record.targetPrs ??\r\n record.target_prs;\r\n return Array.isArray(raw) ? raw.length : 0;\r\n}\r\n\r\nexport function extractEmbeddedWorkerFinalResultRecord(\r\n value: string,\r\n): Record<string, unknown> | null {\r\n const trimmed = value.trim();\r\n if (!trimmed) return null;\r\n\r\n const direct = tryParseJsonObject(trimmed);\r\n if (direct) return direct;\r\n\r\n const candidates: Record<string, unknown>[] = [];\r\n\r\n const fenceRe = /```(?:json)?\\s*([\\s\\S]*?)```/gi;\r\n let fenceMatch: RegExpExecArray | null;\r\n while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {\r\n const fromFence = tryParseJsonObject(fenceMatch[1] ?? \"\");\r\n if (fromFence) candidates.push(fromFence);\r\n }\r\n\r\n const firstBrace = trimmed.indexOf(\"{\");\r\n const lastBrace = trimmed.lastIndexOf(\"}\");\r\n if (firstBrace >= 0 && lastBrace > firstBrace) {\r\n const slice = tryParseJsonObject(trimmed.slice(firstBrace, lastBrace + 1));\r\n if (slice) candidates.push(slice);\r\n }\r\n\r\n if (candidates.length === 0) return null;\r\n\r\n let best = candidates[candidates.length - 1]!;\r\n let bestScore = reconciliationEntryCount(best);\r\n for (const candidate of candidates) {\r\n const score = reconciliationEntryCount(candidate);\r\n if (score > bestScore) {\r\n best = candidate;\r\n bestScore = score;\r\n }\r\n }\r\n return best;\r\n}\r\n", "// Runtime mirror of server landing-contract gate (Dalton landing-only / target PRs).\r\n\r\nimport { extractEmbeddedWorkerFinalResultRecord } from \"./worker-final-result-embed.js\";\r\nimport type { WorkerLandingSnapshot } from \"./landing-gate.js\";\r\n\r\nexport type TargetPrOutcome = \"merged\" | \"skipped\" | \"blocked\";\r\n\r\nexport interface TargetPrReconciliation {\r\n prUrl: string;\r\n outcome: TargetPrOutcome;\r\n mergeCommit?: string | null;\r\n reason?: string | null;\r\n}\r\n\r\nexport interface WorkerLandingContract {\r\n landingOnly: boolean;\r\n targetPrUrls: string[];\r\n targetPrUrl?: string | null;\r\n repairEnforceOriginalPr?: boolean;\r\n requiresTargetPrReconciliation?: boolean;\r\n}\r\n\r\nexport type WorkerLandingContractBlockReason =\r\n | \"unrelated_implementation_pr\"\r\n | \"missing_target_pr_reconciliation\"\r\n | \"incomplete_target_pr_landing\"\r\n | \"duplicate_repair_pr\"\r\n | \"missing_repair_target_reconciliation\";\r\n\r\nexport interface WorkerLandingContractVerdict {\r\n blocked: boolean;\r\n reason?: WorkerLandingContractBlockReason;\r\n detail?: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const t = value.trim();\r\n return t.length ? t : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction normalizePrUrl(url: string): string | null {\r\n const m = url\r\n .trim()\r\n .match(/github\\.com\\/([^/]+\\/[^/]+)\\/(?:pull|pulls)\\/(\\d+)/i);\r\n if (!m) return trimOrNull(url);\r\n return `https://github.com/${m[1]}/pull/${m[2]}`;\r\n}\r\n\r\nfunction prUrlSetKey(url: string): string {\r\n const m = url\r\n .trim()\r\n .match(/github\\.com\\/([^/]+\\/[^/]+)\\/(?:pull|pulls)\\/(\\d+)/i);\r\n if (!m) return url.trim().toLowerCase();\r\n return `${m[1].toLowerCase()}/pull/${m[2]}`;\r\n}\r\n\r\nfunction parseReconciliation(finalResult: unknown): TargetPrReconciliation[] {\r\n let record: Record<string, unknown> | null = null;\r\n if (typeof finalResult === \"string\") {\r\n const embedded = extractEmbeddedWorkerFinalResultRecord(finalResult);\r\n if (embedded) record = embedded;\r\n } else if (finalResult && typeof finalResult === \"object\" && !Array.isArray(finalResult)) {\r\n record = finalResult as Record<string, unknown>;\r\n }\r\n if (!record) return [];\r\n const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;\r\n if (!Array.isArray(raw)) return [];\r\n const out: TargetPrReconciliation[] = [];\r\n for (const item of raw) {\r\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\r\n const row = item as Record<string, unknown>;\r\n const prUrl = normalizePrUrl(String(row.prUrl ?? row.pr_url ?? \"\"));\r\n const outcome = trimOrNull(row.outcome);\r\n if (!prUrl || (outcome !== \"merged\" && outcome !== \"skipped\" && outcome !== \"blocked\")) continue;\r\n out.push({\r\n prUrl,\r\n outcome,\r\n mergeCommit: trimOrNull(row.mergeCommit ?? row.merge_commit),\r\n reason: trimOrNull(row.reason),\r\n });\r\n }\r\n return out;\r\n}\r\n\r\n/** Snapshot / structured prUrl only \u2014 not laneExpertise.prUrls citation evidence. */\r\nfunction workerAttachedPrUrls(snapshot: WorkerLandingSnapshot, finalResult: unknown): string[] {\r\n const urls: string[] = [];\r\n const fromSnapshot = normalizePrUrl(trimOrNull(snapshot.prUrl) ?? \"\");\r\n if (fromSnapshot) urls.push(fromSnapshot);\r\n if (finalResult && typeof finalResult === \"object\" && !Array.isArray(finalResult)) {\r\n const record = finalResult as Record<string, unknown>;\r\n const pr = normalizePrUrl(String(record.prUrl ?? record.pr_url ?? \"\"));\r\n if (pr) urls.push(pr);\r\n }\r\n return [...new Set(urls)];\r\n}\r\n\r\nexport function assessWorkerLandingContract(input: {\r\n contract: WorkerLandingContract;\r\n snapshot: WorkerLandingSnapshot;\r\n finalResult?: unknown;\r\n}): WorkerLandingContractVerdict {\r\n const { contract, snapshot } = input;\r\n const finalResult = input.finalResult ?? snapshot.finalResult;\r\n\r\n if (\r\n !contract.landingOnly &&\r\n contract.targetPrUrls.length === 0 &&\r\n !contract.repairEnforceOriginalPr\r\n ) {\r\n return { blocked: false };\r\n }\r\n if (!hasFinalResult(finalResult)) {\r\n const requiresEarly =\r\n contract.requiresTargetPrReconciliation ??\r\n (contract.landingOnly ||\r\n Boolean(contract.repairEnforceOriginalPr) ||\r\n contract.targetPrUrls.length > 0);\r\n if (requiresEarly && contract.targetPrUrls.length > 0) {\r\n return {\r\n blocked: true,\r\n reason: \"missing_target_pr_reconciliation\",\r\n detail: `Final result required to reconcile target PR(s): ${contract.targetPrUrls.join(\", \")}`,\r\n };\r\n }\r\n return { blocked: false };\r\n }\r\n\r\n const requiresTargetPrReconciliation =\r\n contract.requiresTargetPrReconciliation ??\r\n (contract.landingOnly ||\r\n Boolean(contract.repairEnforceOriginalPr) ||\r\n contract.targetPrUrls.length > 0);\r\n\r\n if (!requiresTargetPrReconciliation && !contract.repairEnforceOriginalPr) {\r\n return { blocked: false };\r\n }\r\n\r\n const repairTarget = contract.repairEnforceOriginalPr\r\n ? normalizePrUrl(trimOrNull(contract.targetPrUrl) ?? \"\") ??\r\n (contract.targetPrUrls.length === 1\r\n ? normalizePrUrl(contract.targetPrUrls[0]!)\r\n : null)\r\n : null;\r\n if (repairTarget) {\r\n const workerPrs = workerAttachedPrUrls(snapshot, finalResult);\r\n const supersedes =\r\n finalResult &&\r\n typeof finalResult === \"object\" &&\r\n !Array.isArray(finalResult) &&\r\n (finalResult as Record<string, unknown>).supersedesOriginalTargetPr === true;\r\n if (!supersedes) {\r\n for (const pr of workerPrs) {\r\n if (pr !== repairTarget) {\r\n return {\r\n blocked: true,\r\n reason: \"duplicate_repair_pr\",\r\n detail: `Repair worker opened or attached PR ${pr} instead of canonical target ${repairTarget}`,\r\n };\r\n }\r\n }\r\n }\r\n const reconciliation = parseReconciliation(finalResult);\r\n const entry = reconciliation.find((r) => r.prUrl === repairTarget);\r\n if (\r\n !entry ||\r\n (entry.outcome !== \"merged\" &&\r\n !(entry.reason?.trim() && (entry.outcome === \"skipped\" || entry.outcome === \"blocked\")))\r\n ) {\r\n return {\r\n blocked: true,\r\n reason: \"missing_repair_target_reconciliation\",\r\n detail: `Repair worker must reconcile target PR ${repairTarget}`,\r\n };\r\n }\r\n }\r\n\r\n const reconciliation = parseReconciliation(finalResult);\r\n const byUrl = new Map(\r\n reconciliation.map((r) => [prUrlSetKey(r.prUrl), r] as const),\r\n );\r\n const targetSet = new Set(\r\n contract.targetPrUrls.map((u) => prUrlSetKey(normalizePrUrl(u) ?? u)).filter(Boolean),\r\n );\r\n const attachedPrs = workerAttachedPrUrls(snapshot, finalResult);\r\n\r\n if (contract.landingOnly) {\r\n for (const pr of attachedPrs) {\r\n if (targetSet.size > 0 && !targetSet.has(prUrlSetKey(pr))) {\r\n return {\r\n blocked: true,\r\n reason: \"unrelated_implementation_pr\",\r\n detail: `Landing-only worker attached unrelated PR ${pr}`,\r\n };\r\n }\r\n if (targetSet.size === 0) {\r\n return {\r\n blocked: true,\r\n reason: \"unrelated_implementation_pr\",\r\n detail: \"Landing-only worker must not open new implementation PRs\",\r\n };\r\n }\r\n }\r\n }\r\n\r\n if (contract.targetPrUrls.length === 0) return { blocked: false };\r\n\r\n const missing: string[] = [];\r\n for (const target of contract.targetPrUrls) {\r\n const key = prUrlSetKey(normalizePrUrl(target) ?? target);\r\n const entry = byUrl.get(key);\r\n if (!entry) {\r\n missing.push(key);\r\n continue;\r\n }\r\n if (entry.outcome !== \"merged\" && !entry.reason?.trim()) {\r\n missing.push(key);\r\n }\r\n }\r\n\r\n if (missing.length > 0) {\r\n return {\r\n blocked: true,\r\n reason: missing.every((u) => byUrl.has(u))\r\n ? \"incomplete_target_pr_landing\"\r\n : \"missing_target_pr_reconciliation\",\r\n detail: `Target PR reconciliation incomplete: ${missing.join(\", \")}`,\r\n };\r\n }\r\n\r\n return { blocked: false };\r\n}\r\n\r\nexport function landingContractAttentionReason(\r\n verdict: WorkerLandingContractVerdict,\r\n): string | undefined {\r\n if (!verdict.blocked) return undefined;\r\n return verdict.detail ?? verdict.reason;\r\n}\r\n", "import { parseHeartbeat, terminalFinalResultFromHeartbeat } from \"./heartbeat.js\";\r\nimport { parseHarnessStream } from \"./stream.js\";\r\nimport { classifyExitFailure } from \"./exit-classify.js\";\r\nimport { assessExitedWorkerSalvage } from \"./exited-salvage.js\";\r\nimport { computeGitAncestry, type GitAncestry, gitStatusShort } from \"./git.js\";\r\nimport { assessWorkerLanding, landingAttentionReason } from \"./landing-gate.js\";\r\nimport {\r\n assessWorkerLandingContract,\r\n landingContractAttentionReason,\r\n type WorkerLandingContract,\r\n type TargetPrReconciliation,\r\n} from \"./landing-contract-gate.js\";\r\nimport { extractEmbeddedWorkerFinalResultRecord } from \"./worker-final-result-embed.js\";\r\nimport {\r\n fileMtime,\r\n fileSize,\r\n isPidAlive,\r\n latestIso,\r\n secsAgo,\r\n tailFile,\r\n} from \"./util.js\";\r\n\r\nexport const NO_START_MS = 180_000;\r\nexport const STALE_MS = 600_000;\r\n\r\nexport interface WorkerAttention {\r\n state: \"done\" | \"needs_attention\" | \"blocked\" | \"stale\" | \"ok\";\r\n reason: string;\r\n}\r\n\r\n/** Snapshot of Lane A policy injection at worker spawn (from dispatch-next). */\r\nexport interface InstructionPolicyEvidenceSnapshot {\r\n fingerprint?: string;\r\n ruleSlugs?: string[];\r\n globalRuleCount?: number;\r\n personaRuleCount?: number;\r\n explicitKindCount?: number;\r\n invariantCount?: number;\r\n markdownChars?: number;\r\n injectedAt?: string;\r\n}\r\n\r\n/** Snapshot of task-anchored context envelope injection at worker spawn. */\r\nexport interface ContextEnvelopeEvidenceSnapshot {\r\n anchorTaskId?: string;\r\n envelopeGeneratedAt?: string;\r\n injectedAt?: string;\r\n hasPersonaBlock?: boolean;\r\n personaSlug?: string | null;\r\n operatingRuleCount?: number;\r\n memoryHitCount?: number;\r\n markdownChars?: number;\r\n source?: \"dispatch_injection\" | \"tool_call\";\r\n}\r\n\r\n/** Snapshot of anchored persona context-envelope injection at worker spawn. */\r\nexport interface PersonaContextEvidenceSnapshot {\r\n expectedPersonaSlug?: string;\r\n injectedPersonaSlug?: string;\r\n displayName?: string;\r\n operatingRuleCount?: number;\r\n anchorTaskId?: string;\r\n envelopeGeneratedAt?: string;\r\n injectedAt?: string;\r\n markdownChars?: number;\r\n}\r\n\r\n/** Dispatch-time retrieval probe replayed on harness completion. */\r\nexport interface HarnessMemoryQualityCaptureSnapshot {\r\n memoryQuery: string;\r\n hitCount: number;\r\n miss: boolean;\r\n capturedAt: string;\r\n retrievalEvidence?: Record<string, unknown> | null;\r\n /** P7 privacy-safe prompt block (trace summary + live-verification nudges). */\r\n promptMarkdown?: string | null;\r\n}\r\n\r\nexport interface HarnessWorkerRecord {\r\n name: string;\r\n runId: string;\r\n status: string;\r\n pid?: number;\r\n model?: string;\r\n branch: string;\r\n worktreePath: string;\r\n workerDir: string;\r\n stdoutPath: string;\r\n stderrPath: string;\r\n heartbeatPath: string;\r\n ownedPaths?: string[];\r\n agentOsId?: string;\r\n taskId?: string;\r\n planId?: string;\r\n /** Lane A policy fingerprint when dispatch injected operating rules. */\r\n instructionPolicyFingerprint?: string;\r\n instructionPolicyEvidence?: InstructionPolicyEvidenceSnapshot;\r\n memoryQualityCapture?: HarnessMemoryQualityCaptureSnapshot;\r\n personaSlug?: string;\r\n personaEvidence?: PersonaContextEvidenceSnapshot;\r\n contextEnvelopeEvidence?: ContextEnvelopeEvidenceSnapshot;\r\n leaseOwner?: string;\r\n /** Fencing token from claim \u2014 sent on renew/completion when set. */\r\n leaseToken?: string;\r\n dispatched?: boolean;\r\n startedAt?: string;\r\n /** Routing audit \u2014 which rule selected model/provider (dispatch inference). */\r\n routingRule?: string;\r\n requestedModel?: string;\r\n /** Orchestration provider/model/auth-source/cost audit (no OAuth secrets). */\r\n orchestrationAudit?: import(\"./orchestration-providers/types.js\").OrchestrationRoutingAudit;\r\n /** Board task metadata for landing/PR-handoff gates (set at dispatch). */\r\n executorRef?: string;\r\n parentTaskId?: string;\r\n taskTitle?: string;\r\n taskPrUrl?: string;\r\n /** Canonical target PR for repair workers (must not spawn duplicate PRs). */\r\n repairTargetPrUrl?: string;\r\n repairTargetBranch?: string;\r\n /** Set when stale-reconcile patches a dead/stale worker record. */\r\n reconciledAt?: string;\r\n reconcileReason?: string;\r\n /** Last heartbeat blocker text successfully synced to plan-progress-sync (dedupe). */\r\n lastSyncedHeartbeatBlocker?: string;\r\n /**\r\n * Set when the most recent AgentOS completion replay for this finished worker\r\n * was rejected (e.g. a revoked / expired / cross-workspace runner token) or\r\n * otherwise failed. While set, the worker is NOT treated as cleanly done:\r\n * `finalizeStaleRuns` keeps the run non-terminal and the board surfaces it.\r\n * Cleared once the completion is acknowledged (2xx). Local-only \u2014 never sent\r\n * to the server as part of the worker's intrinsic status.\r\n */\r\n completionBlocker?: string;\r\n /** ISO timestamp when `/harness/completion` returned 2xx for this worker. */\r\n completionReportedAt?: string;\r\n /** Snapshot from the acknowledged completion POST \u2014 local-only. */\r\n completionSnapshot?: { finalResult?: unknown; prUrl?: string | null; summary?: string | null };\r\n /** Audit tag for how `completionReportedAt` was set (`tryCompleteWorker`, `board-task-*`). */\r\n completionAckSource?: string;\r\n /** Local mirror of the last completion POST outcome. */\r\n completionOutcome?: \"acknowledged\" | \"rejected\";\r\n /** Truncated JSON body from the last acknowledged completion response. */\r\n completionResponse?: unknown;\r\n /**\r\n * Direct/local worker with no board linkage \u2014 must not be mistaken for an\r\n * AgentTask-backed harness worker in completion or dispatch paths.\r\n */\r\n localOnly?: boolean;\r\n /** Sidecar PID when detached; used for observability only. */\r\n completionSidecarPid?: number;\r\n completionSidecarSpawnFailedAt?: string;\r\n /** One-off helper paths removed before completion (`kynver worker discard-disposable`). */\r\n disposableArtifactsRemoved?: string[];\r\n /** Physical pool label frozen at spawn for orchestration usage attribution. */\r\n boxKind?: string;\r\n boxId?: string;\r\n /** Runner/daemon identity frozen at spawn (KYNVER_RUNTIME_ID). */\r\n runtimeId?: string;\r\n}\r\n\r\nexport interface RawHarnessWorkerStatus {\r\n runId: string;\r\n worker: string;\r\n pid?: number;\r\n alive: boolean;\r\n status: string;\r\n attention: WorkerAttention;\r\n branch: string;\r\n worktreePath: string;\r\n ownedPaths?: string[];\r\n stdoutBytes: number;\r\n stderrBytes: number;\r\n heartbeatBytes: number;\r\n firstEventAt: string | null;\r\n lastEventAt: string | null;\r\n lastActivityAt: string | null;\r\n currentTool: string | null;\r\n heartbeatCount: number;\r\n lastHeartbeatAt: string | null;\r\n lastHeartbeatPhase: string | null;\r\n lastHeartbeatSummary: string | null;\r\n heartbeatBlocker: string | null;\r\n /** Parser-detected timestamp anomalies (e.g., future heartbeat ts). */\r\n timestampAnomalies?: Array<{\r\n kind: \"future_heartbeat_timestamp\";\r\n observedAt: string;\r\n clampedTo: string;\r\n }>;\r\n finalResult: unknown;\r\n error?: string;\r\n changedFiles: string[];\r\n gitAncestry: GitAncestry;\r\n /** Set by PR-ready handoff before completion is posted. */\r\n prUrl?: string;\r\n headCommit?: string;\r\n /** Paths removed via `kynver worker discard-disposable` before completion POST. */\r\n disposableArtifactsRemoved?: string[];\r\n /** Fencing token from claim \u2014 echoed on completion when set. */\r\n leaseToken?: string;\r\n /** Lane A policy fields echoed on completion status for mirror recovery. */\r\n instructionPolicyFingerprint?: string | null;\r\n instructionPolicyEvidence?: InstructionPolicyEvidenceSnapshot | null;\r\n /** Model the worker was launched with \u2014 echoed from worker.json for usage tracking. */\r\n model?: string | null;\r\n /** Orchestration provider key (codex | cursor | claude) \u2014 echoed from worker.json. */\r\n provider?: string | null;\r\n /** Physical pool label \u2014 ghost | forge (runtime \u2265 0.1.115). */\r\n boxKind?: string | null;\r\n boxId?: string | null;\r\n /** Runner/daemon identity echoed from worker.json. */\r\n runtimeId?: string | null;\r\n personaSlug?: string | null;\r\n /** True when dispatch-next spawned the worker on a daemon tick. */\r\n dispatched?: boolean | null;\r\n localOnly?: boolean | null;\r\n}\r\n\r\nexport interface WorkerStatusOptions {\r\n /** Branch ref for ancestry when baseCommit is not set. */\r\n base?: string;\r\n /** Pinned SHA from run creation \u2014 preferred for ancestry vs a moving branch tip. */\r\n baseCommit?: string;\r\n}\r\n\r\nexport function computeAttention(input: {\r\n alive: boolean;\r\n finalResult: unknown;\r\n firstEventAt: string | null;\r\n stdoutBytes: number;\r\n stderrBytes?: number;\r\n heartbeatBytes: number;\r\n lastActivityAt: string | null;\r\n heartbeatBlocker: string | null;\r\n startedAt?: string;\r\n /** stderr tail / parsed error for a worker that died without a final result. */\r\n error?: string | null;\r\n changedFiles?: string[];\r\n gitAncestry?: GitAncestry | null;\r\n completionBlocker?: string | null;\r\n landingContract?: WorkerLandingContract | null;\r\n prUrl?: string | null;\r\n localOnly?: boolean;\r\n taskId?: string | null;\r\n agentOsId?: string | null;\r\n reconcileReason?: string | null;\r\n}): WorkerAttention {\r\n const now = Date.now();\r\n if (input.completionBlocker && !isSkippedTerminalCompletionBlocker(input.completionBlocker)) {\r\n return { state: \"blocked\", reason: input.completionBlocker };\r\n }\r\n if (input.finalResult) {\r\n if (input.localOnly && hasMergedTargetPrReconciliation(input.finalResult)) {\r\n return { state: \"done\", reason: \"local-only worker superseded by merged PR\" };\r\n }\r\n const landingSnapshot = {\r\n finalResult: input.finalResult,\r\n changedFiles: input.changedFiles ?? [],\r\n gitAncestry: input.gitAncestry ?? null,\r\n prUrl: input.prUrl ?? null,\r\n };\r\n const landing = assessWorkerLanding(landingSnapshot);\r\n if (landing.blocked) {\r\n const detail = landingAttentionReason(landing);\r\n return {\r\n state: \"needs_attention\",\r\n reason: landing.reason\r\n ? `landing blocked (${landing.reason}): ${detail}`\r\n : `landing blocked: ${detail}`,\r\n };\r\n }\r\n if (input.landingContract) {\r\n const contractVerdict = assessWorkerLandingContract({\r\n contract: input.landingContract,\r\n snapshot: landingSnapshot,\r\n finalResult: input.finalResult,\r\n });\r\n const contractDetail = landingContractAttentionReason(contractVerdict);\r\n if (contractDetail) {\r\n return {\r\n state: \"needs_attention\",\r\n reason: contractVerdict.reason\r\n ? `landing contract (${contractVerdict.reason}): ${contractDetail}`\r\n : `landing contract: ${contractDetail}`,\r\n };\r\n }\r\n }\r\n return { state: \"done\", reason: \"final result recorded\" };\r\n }\r\n if (!input.alive) {\r\n if (isAbandonedEmptyWorker(input)) {\r\n return { state: \"done\", reason: \"empty abandoned worker record\" };\r\n }\r\n // A worker that exited without a final result is not always a silent stall:\r\n // a recognizable startup/config failure (model/provider rejection, missing\r\n // CLI, auth) is a structural blocker, not a generic needs_attention.\r\n const classified = classifyExitFailure(input.error);\r\n if (classified) return { state: \"blocked\", reason: classified.reason };\r\n const salvage = assessExitedWorkerSalvage({\r\n alive: false,\r\n finalResult: null,\r\n changedFiles: input.changedFiles,\r\n gitAncestry: input.gitAncestry,\r\n });\r\n if (salvage?.salvageable) {\r\n const tail = input.error?.trim();\r\n return {\r\n state: \"needs_attention\",\r\n reason: tail ? `${salvage.attentionReason} (${tail})` : salvage.attentionReason,\r\n };\r\n }\r\n const tail = input.error?.trim();\r\n return {\r\n state: \"needs_attention\",\r\n reason: tail\r\n ? `process exited without a final result: ${tail}`\r\n : salvage?.attentionReason ?? \"process exited without a final result\",\r\n };\r\n }\r\n if (input.heartbeatBlocker) {\r\n return { state: \"blocked\", reason: `worker heartbeat reported blocker: ${input.heartbeatBlocker}` };\r\n }\r\n const startMs = input.startedAt ? Date.parse(input.startedAt) : NaN;\r\n if (\r\n !input.firstEventAt &&\r\n input.stdoutBytes === 0 &&\r\n input.heartbeatBytes === 0 &&\r\n Number.isFinite(startMs) &&\r\n now - startMs > NO_START_MS\r\n ) {\r\n return { state: \"needs_attention\", reason: `no first stream event ${secsAgo(startMs)}s after start` };\r\n }\r\n const actMs = input.lastActivityAt ? Date.parse(input.lastActivityAt) : NaN;\r\n if (Number.isFinite(actMs) && now - actMs > STALE_MS) {\r\n return { state: \"stale\", reason: `no log/event/heartbeat activity for ${secsAgo(actMs)}s` };\r\n }\r\n return { state: \"ok\", reason: \"recent activity\" };\r\n}\r\n\r\nfunction isSkippedTerminalCompletionBlocker(reason: string | null | undefined): boolean {\r\n const text = reason?.trim();\r\n if (!text) return false;\r\n return /completion acknowledged but board not advanced/i.test(text) && /task already terminal/i.test(text);\r\n}\r\n\r\nfunction isAbandonedEmptyWorker(input: {\r\n finalResult: unknown;\r\n stdoutBytes: number;\r\n stderrBytes?: number;\r\n heartbeatBytes: number;\r\n changedFiles?: string[];\r\n error?: string | null;\r\n taskId?: string | null;\r\n agentOsId?: string | null;\r\n reconcileReason?: string | null;\r\n}): boolean {\r\n if (input.finalResult) return false;\r\n if (input.taskId || input.agentOsId) return false;\r\n if (input.stdoutBytes > 0 || (input.stderrBytes ?? 0) > 0 || input.heartbeatBytes > 0) return false;\r\n if (input.error?.trim()) return false;\r\n if ((input.changedFiles ?? []).some((line) => line.trim())) return false;\r\n return /empty worker dir|marked abandoned/i.test(input.reconcileReason ?? \"\");\r\n}\r\n\r\nfunction hasMergedTargetPrReconciliation(value: unknown): boolean {\r\n let record: Record<string, unknown> | null = null;\r\n if (typeof value === \"string\") record = extractEmbeddedWorkerFinalResultRecord(value);\r\n else if (value && typeof value === \"object\" && !Array.isArray(value)) record = value as Record<string, unknown>;\r\n if (!record) return false;\r\n const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;\r\n if (!Array.isArray(raw)) return false;\r\n return raw.some((item): item is TargetPrReconciliation => {\r\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return false;\r\n return String((item as Record<string, unknown>).outcome ?? \"\").trim() === \"merged\";\r\n });\r\n}\r\n\r\nfunction resolveFinalResult(\r\n worker: HarnessWorkerRecord,\r\n parsedFinalResult: unknown,\r\n heartbeat: ReturnType<typeof parseHeartbeat>,\r\n): unknown {\r\n const ackSnapshot = worker.completionSnapshot?.finalResult;\r\n if (worker.completionAckSource === \"local-pr-merged-reconcile\" && ackSnapshot !== undefined && ackSnapshot !== null) {\r\n return ackSnapshot;\r\n }\r\n if (parsedFinalResult) return parsedFinalResult;\r\n if (ackSnapshot !== undefined && ackSnapshot !== null) return ackSnapshot;\r\n return terminalFinalResultFromHeartbeat(heartbeat);\r\n}\r\n\r\nexport function computeWorkerStatus(worker: HarnessWorkerRecord, options: WorkerStatusOptions = {}): RawHarnessWorkerStatus {\r\n const parsed = parseHarnessStream(worker.stdoutPath);\r\n const heartbeat = parseHeartbeat(worker.heartbeatPath);\r\n const completionAcknowledged =\r\n typeof worker.completionReportedAt === \"string\" && worker.completionReportedAt.trim().length > 0;\r\n const finalResult = resolveFinalResult(worker, parsed.finalResult, heartbeat);\r\n const alive = completionAcknowledged ? false : isPidAlive(worker.pid);\r\n const stdoutBytes = fileSize(worker.stdoutPath);\r\n const stderrBytes = fileSize(worker.stderrPath);\r\n const heartbeatBytes = fileSize(worker.heartbeatPath);\r\n const changedFiles = gitStatusShort(worker.worktreePath);\r\n const gitAncestry = computeGitAncestry(worker.worktreePath, {\r\n base: options.base,\r\n baseCommit: options.baseCommit,\r\n });\r\n const lastActivityAt = latestIso([\r\n parsed.lastEventAt,\r\n heartbeat.lastHeartbeatAt,\r\n fileMtime(worker.stdoutPath),\r\n fileMtime(worker.stderrPath),\r\n fileMtime(worker.heartbeatPath),\r\n ]);\r\n // The error surfaced when a worker died without a final result: the parsed\r\n // stream error, else the stderr tail. Computed before attention so a startup/\r\n // config failure can be classified as a structured blocker.\r\n const error =\r\n parsed.error ||\r\n (!alive && !finalResult ? tailFile(worker.stderrPath, 10).trim() || undefined : undefined);\r\n const completionBlocker =\r\n typeof worker.completionBlocker === \"string\" && worker.completionBlocker.trim()\r\n ? worker.completionBlocker.trim()\r\n : null;\r\n const effectiveCompletionBlocker = isSkippedTerminalCompletionBlocker(completionBlocker)\r\n ? null\r\n : completionBlocker;\r\n const landingContract: WorkerLandingContract | null = worker.repairTargetPrUrl\r\n ? {\r\n landingOnly: false,\r\n targetPrUrls: [worker.repairTargetPrUrl],\r\n targetPrUrl: worker.repairTargetPrUrl,\r\n repairEnforceOriginalPr: true,\r\n }\r\n : null;\r\n\r\n const attention = computeAttention({\r\n alive,\r\n finalResult,\r\n firstEventAt: parsed.firstEventAt,\r\n stdoutBytes,\r\n stderrBytes,\r\n heartbeatBytes,\r\n lastActivityAt,\r\n heartbeatBlocker: heartbeat.heartbeatBlocker,\r\n startedAt: worker.startedAt,\r\n error,\r\n changedFiles,\r\n gitAncestry,\r\n completionBlocker: effectiveCompletionBlocker,\r\n landingContract,\r\n prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? null,\r\n localOnly: worker.localOnly === true,\r\n taskId: worker.taskId ?? null,\r\n agentOsId: worker.agentOsId ?? null,\r\n reconcileReason: worker.reconcileReason ?? null,\r\n });\r\n const workerStatusLabel =\r\n effectiveCompletionBlocker || attention.state === \"blocked\"\r\n ? \"blocked\"\r\n : completionAcknowledged || attention.state === \"done\"\r\n ? \"done\"\r\n : finalResult\r\n ? \"exited\"\r\n : alive\r\n ? \"running\"\r\n : \"exited\";\r\n return {\r\n runId: worker.runId,\r\n worker: worker.name,\r\n pid: worker.pid,\r\n alive,\r\n status: workerStatusLabel,\r\n attention,\r\n branch: worker.branch,\r\n worktreePath: worker.worktreePath,\r\n ownedPaths: worker.ownedPaths,\r\n stdoutBytes,\r\n stderrBytes,\r\n heartbeatBytes,\r\n firstEventAt: parsed.firstEventAt,\r\n lastEventAt: parsed.lastEventAt,\r\n lastActivityAt,\r\n currentTool: completionAcknowledged ? null : parsed.currentTool,\r\n heartbeatCount: heartbeat.heartbeatCount,\r\n lastHeartbeatAt: heartbeat.lastHeartbeatAt,\r\n lastHeartbeatPhase: heartbeat.lastHeartbeatPhase,\r\n lastHeartbeatSummary: heartbeat.lastHeartbeatSummary,\r\n heartbeatBlocker: heartbeat.heartbeatBlocker,\r\n timestampAnomalies: heartbeat.timestampAnomalies,\r\n finalResult,\r\n error,\r\n changedFiles,\r\n gitAncestry,\r\n instructionPolicyFingerprint: worker.instructionPolicyFingerprint ?? null,\r\n instructionPolicyEvidence: worker.instructionPolicyEvidence ?? null,\r\n model: worker.model ?? worker.orchestrationAudit?.model ?? null,\r\n provider: worker.orchestrationAudit?.provider ?? null,\r\n boxKind: worker.boxKind ?? null,\r\n boxId: worker.boxId ?? null,\r\n runtimeId: worker.runtimeId ?? null,\r\n personaSlug: worker.personaSlug ?? null,\r\n dispatched: worker.dispatched ?? null,\r\n localOnly: worker.localOnly ?? null,\r\n };\r\n}\r\n\r\nexport function isFinishedWorkerStatus(status: RawHarnessWorkerStatus): boolean {\r\n if (status.finalResult) return true;\r\n if (status.alive === false) return true;\r\n if (status.status === \"exited\" || status.status === \"done\") return true;\r\n return false;\r\n}\r\n\r\n/** True when a worker recorded a final result but failed the landing gate. */\r\nexport function isLandingBlockedWorkerStatus(status: RawHarnessWorkerStatus): boolean {\r\n if (!status.finalResult) return false;\r\n return status.attention.state === \"needs_attention\" || status.attention.state === \"blocked\";\r\n}\r\n\r\nexport function deriveRunStatus(fallback: string, workers: Array<{ attention?: string; status?: string }>): string {\r\n if (workers.length === 0) return fallback;\r\n if (workers.some((w) => w.attention === \"needs_attention\" || w.attention === \"stale\" || w.attention === \"blocked\")) {\r\n return \"needs_attention\";\r\n }\r\n if (workers.every((w) => w.status === \"done\")) return \"done\";\r\n if (workers.some((w) => w.status === \"running\")) return \"running\";\r\n return fallback;\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\nimport { computeWorkerStatus } from \"./status.js\";\r\n\r\nfunction pidCommandLine(pid: number | undefined): string | null {\r\n if (!pid || process.platform !== \"linux\") return null;\r\n try {\r\n return readFileSync(`/proc/${pid}/cmdline`, \"utf8\").replace(/\\0/g, \" \");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * PID existence is not enough on long-running hosts: Linux can reuse an old\r\n * worker PID for an unrelated process, which makes stale worker.json records\r\n * look alive and can falsely saturate the global worker gate.\r\n */\r\nexport function workerProcessMatchesRecord(worker: HarnessWorkerRecord): boolean {\r\n if (!worker.pid || process.platform !== \"linux\") return true;\r\n const cmdline = pidCommandLine(worker.pid);\r\n if (!cmdline) return false;\r\n const probes = [worker.worktreePath, worker.workerDir, worker.heartbeatPath].filter(\r\n (value): value is string => typeof value === \"string\" && value.trim().length > 0,\r\n );\r\n return probes.some((probe) => cmdline.includes(probe));\r\n}\r\n\r\n/**\r\n * Whether a worker still occupies a machine-wide harness capacity slot.\r\n * Ignores completion-acknowledged workers even when the recorded PID was reused.\r\n */\r\nexport function isActiveHarnessWorker(worker: HarnessWorkerRecord): boolean {\r\n if (typeof worker.completionBlocker === \"string\" && worker.completionBlocker.trim()) {\r\n return false;\r\n }\r\n const status = computeWorkerStatus(worker);\r\n if (status.alive && !workerProcessMatchesRecord(worker)) return false;\r\n return status.alive && !status.finalResult && status.attention.state !== \"done\";\r\n}\r\n", "import os from \"node:os\";\r\nimport { readMemAvailableBytes } from \"./bounded-build/meminfo.js\";\r\nimport path from \"node:path\";\r\nimport { loadUserConfig, type KynverUserConfig } from \"./config.js\";\r\nimport { resolveBoxKindFromConfig } from \"./box-identity.js\";\r\nimport type { WorkerCapSource } from \"./worker-cap-source.js\";\r\nimport { resolveWorkerCap } from \"./worker-cap-source.js\";\r\nimport type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport { observeRunnerDiskGate } from \"./disk-gate.js\";\r\nimport { listRunRecords, loadRun, runDirectory, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { listRunWorkerNames } from \"./run-worker-index.js\";\r\nimport { isActiveHarnessWorker, workerProcessMatchesRecord } from \"./harness-worker-active.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport { workerProcessMatchesRecord };\r\n\r\n/** Default RAM budget per worker (~500 MiB, dogfood measured). Internal \u2014 not a setup knob. */\r\nexport const DEFAULT_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;\r\n\r\n/** Keep headroom for OS / IDE. Internal \u2014 not a setup knob. */\r\nexport const DEFAULT_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;\r\n\r\n/** Fraction of total RAM used when auto-sizing worker cap. Internal. */\r\nexport const DEFAULT_MEM_UTILIZATION = 0.85;\r\n\r\n/** Auto cap when the user has not set maxConcurrentWorkers (safety on huge hosts). */\r\nexport const AUTO_MAX_WORKERS_CEILING = 64;\r\n\r\nexport interface RunnerResourceGateShape {\r\n ok: boolean;\r\n totalMemBytes: number;\r\n freeMemBytes: number;\r\n memReserveBytes: number;\r\n perWorkerMemBytes: number;\r\n configuredMaxWorkers: number | null;\r\n /** Where the effective worker cap was resolved (workspace override, env, config, or auto). */\r\n workerCapSource: WorkerCapSource;\r\n /** Physical pool for this host (`forge` | `ghost`). */\r\n boxKind: string;\r\n autoCap: number;\r\n capacityWorkers: number;\r\n maxConcurrentWorkers: number;\r\n activeWorkers: number;\r\n slotsAvailable: number;\r\n reason: string | null;\r\n /** Present unless `KYNVER_RESOURCE_GATE_SKIP_DISK=1`. */\r\n diskGate?: DispatchNextDiskGateShape;\r\n}\r\n\r\nexport interface ObserveResourceGateInput {\r\n runId: string;\r\n config?: KynverUserConfig;\r\n /** Command Center / workspace override \u2014 wins over local config when set. */\r\n configuredMaxWorkersOverride?: number | null;\r\n /** Override active worker count (tests). */\r\n activeWorkers?: number;\r\n totalMemBytes?: number;\r\n freeMemBytes?: number;\r\n diskPath?: string;\r\n skipDiskGate?: boolean;\r\n}\r\n\r\nfunction positiveInt(value: unknown, fallback: number): number {\r\n const n = Number(value);\r\n if (!Number.isFinite(n) || n <= 0) return fallback;\r\n return Math.floor(n);\r\n}\r\n\r\nfunction resolveResourceConfig(\r\n config: KynverUserConfig = loadUserConfig(),\r\n configuredMaxWorkersOverride?: number | null,\r\n totalMemBytes?: number,\r\n) {\r\n const perWorkerMemBytes = positiveInt(config.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES);\r\n const memReserveBytes = positiveInt(config.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES);\r\n const memUtilization = Math.min(\r\n 1,\r\n Math.max(0.1, Number(config.memUtilization) > 0 ? Number(config.memUtilization) : DEFAULT_MEM_UTILIZATION),\r\n );\r\n const cap = resolveWorkerCap({\r\n config,\r\n configuredMaxWorkersOverride,\r\n totalMemBytes: totalMemBytes ?? os.totalmem(),\r\n });\r\n return {\r\n perWorkerMemBytes,\r\n memReserveBytes,\r\n memUtilization,\r\n configuredMaxWorkers: cap.configuredMaxWorkers,\r\n autoCap: cap.autoCap,\r\n workerCapSource: cap.workerCapSource,\r\n };\r\n}\r\n\r\n/** How many workers this host could run from RAM alone (before a user cap). */\r\nexport function computeAutoMaxWorkers(\r\n totalMemBytes: number,\r\n opts: { perWorkerMemBytes?: number; memReserveBytes?: number; memUtilization?: number } = {},\r\n): number {\r\n const perWorkerMemBytes = opts.perWorkerMemBytes ?? DEFAULT_PER_WORKER_MEM_BYTES;\r\n const memReserveBytes = opts.memReserveBytes ?? DEFAULT_MEM_RESERVE_BYTES;\r\n const memUtilization = opts.memUtilization ?? DEFAULT_MEM_UTILIZATION;\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);\r\n const raw = Math.max(1, Math.floor(budgetBytes / perWorkerMemBytes));\r\n return Math.min(raw, AUTO_MAX_WORKERS_CEILING);\r\n}\r\n\r\nfunction readAvailableMemBytes(): number {\r\n return readMemAvailableBytes();\r\n}\r\n\r\n/** Count alive, still-executing workers in a single run record. */\r\nfunction countActiveWorkersForRun(run: HarnessRunRecord): number {\r\n let active = 0;\r\n for (const name of listRunWorkerNames(run)) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectory(run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker || !isActiveHarnessWorker(worker)) continue;\r\n active++;\r\n }\r\n return active;\r\n}\r\n\r\n/** Count active workers in ONE run (kept for callers/tests scoped to a run). */\r\nexport function countActiveWorkers(runId: string): number {\r\n return countActiveWorkersForRun(loadRun(runId));\r\n}\r\n\r\n/**\r\n * Count active workers across EVERY run on disk. The harness creates a new run\r\n * per task, so a per-run count let concurrent runs each believe the machine was\r\n * idle \u2014 the configured cap was never a real global ceiling (the \"spawns 4 or\r\n * infinity, never N\" bug). This machine-wide count is what the gate must use.\r\n */\r\nexport function countActiveWorkersGlobal(): number {\r\n let active = 0;\r\n for (const run of listRunRecords()) active += countActiveWorkersForRun(run);\r\n return active;\r\n}\r\n\r\n/**\r\n * Compute how many workers this host can run and how many dispatch slots remain.\r\n * Uses total RAM for steady-state capacity and free RAM as a hard safety gate.\r\n */\r\nexport function observeRunnerResourceGate(input: ObserveResourceGateInput): RunnerResourceGateShape {\r\n const config = input.config ?? loadUserConfig();\r\n const totalMemBytes = input.totalMemBytes ?? os.totalmem();\r\n const { perWorkerMemBytes, memReserveBytes, memUtilization, configuredMaxWorkers, autoCap: resolvedAutoCap, workerCapSource } =\r\n resolveResourceConfig(config, input.configuredMaxWorkersOverride, totalMemBytes);\r\n const boxKind = resolveBoxKindFromConfig(config);\r\n const freeMemBytes = input.freeMemBytes ?? readAvailableMemBytes();\r\n // Active count is GLOBAL across all runs (see countActiveWorkersGlobal), so the\r\n // cap is a true machine-wide ceiling rather than per-run.\r\n const activeWorkers = input.activeWorkers ?? countActiveWorkersGlobal();\r\n\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);\r\n const capacityFromTotal = Math.max(0, Math.floor(budgetBytes / perWorkerMemBytes));\r\n const capacityFromFree = Math.max(0, Math.floor(Math.max(0, freeMemBytes - memReserveBytes) / perWorkerMemBytes));\r\n\r\n const autoCap = resolvedAutoCap;\r\n const targetCap = configuredMaxWorkers ?? autoCap;\r\n const maxConcurrentWorkers = Math.max(0, Math.min(targetCap, capacityFromTotal));\r\n const slotsByCapacity = Math.max(0, maxConcurrentWorkers - activeWorkers);\r\n // capacityFromFree is ADDITIONAL headroom: free/available RAM already excludes\r\n // memory held by running workers, so we must NOT subtract activeWorkers again.\r\n // Doing so (the old `capacityFromFree - activeWorkers`) double-counted active\r\n // workers and collapsed dispatch to a handful of slots under load.\r\n const slotsByFreeMem = capacityFromFree;\r\n let slotsAvailable = Math.min(slotsByCapacity, slotsByFreeMem);\r\n\r\n const skipDisk = input.skipDiskGate || process.env.KYNVER_RESOURCE_GATE_SKIP_DISK === \"1\";\r\n const diskGate = skipDisk\r\n ? undefined\r\n : observeRunnerDiskGate({\r\n diskPath:\r\n input.diskPath?.trim() ||\r\n process.env.KYNVER_DISK_GUARD_PATH?.trim() ||\r\n \"/\",\r\n });\r\n if (diskGate && !diskGate.ok) slotsAvailable = 0;\r\n\r\n let reason: string | null = null;\r\n if (slotsAvailable <= 0) {\r\n if (diskGate && !diskGate.ok) {\r\n reason = diskGate.reason ?? \"disk gate blocked worker admission\";\r\n } else if (activeWorkers >= maxConcurrentWorkers) {\r\n reason = `at worker limit (${activeWorkers}/${maxConcurrentWorkers} running)`;\r\n } else if (capacityFromFree <= 0) {\r\n reason = \"insufficient free memory \u2014 waiting for workers to finish\";\r\n } else {\r\n reason = \"no worker slots available\";\r\n }\r\n }\r\n\r\n return {\r\n ok: slotsAvailable > 0,\r\n totalMemBytes,\r\n freeMemBytes,\r\n memReserveBytes,\r\n perWorkerMemBytes,\r\n configuredMaxWorkers,\r\n workerCapSource,\r\n boxKind,\r\n autoCap,\r\n capacityWorkers: capacityFromTotal,\r\n maxConcurrentWorkers,\r\n activeWorkers,\r\n slotsAvailable,\r\n reason,\r\n ...(diskGate ? { diskGate } : {}),\r\n };\r\n}\r\n", "import type { KynverUserConfig } from \"./config.js\";\r\nimport {\r\n AUTO_MAX_WORKERS_CEILING,\r\n computeAutoMaxWorkers,\r\n DEFAULT_MEM_RESERVE_BYTES,\r\n DEFAULT_MEM_UTILIZATION,\r\n DEFAULT_PER_WORKER_MEM_BYTES,\r\n} from \"./resource-gate.js\";\r\n\r\nexport type WorkerCapSource = \"workspace_override\" | \"env\" | \"config\" | \"auto\";\r\n\r\nexport interface ResolvedWorkerCap {\r\n configuredMaxWorkers: number | null;\r\n autoCap: number;\r\n workerCapSource: WorkerCapSource;\r\n}\r\n\r\nfunction positiveInt(value: unknown, fallback: number): number {\r\n const n = Number(value);\r\n if (!Number.isFinite(n) || n <= 0) return fallback;\r\n return Math.floor(n);\r\n}\r\n\r\nexport function resolveWorkerCap(\r\n input: {\r\n config?: KynverUserConfig;\r\n configuredMaxWorkersOverride?: number | null;\r\n totalMemBytes: number;\r\n env?: NodeJS.ProcessEnv;\r\n },\r\n): ResolvedWorkerCap {\r\n const config = input.config ?? {};\r\n const env = input.env ?? process.env;\r\n const perWorkerMemBytes = positiveInt(config.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES);\r\n const memReserveBytes = positiveInt(config.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES);\r\n const memUtilization = Math.min(\r\n 1,\r\n Math.max(0.1, Number(config.memUtilization) > 0 ? Number(config.memUtilization) : DEFAULT_MEM_UTILIZATION),\r\n );\r\n const autoCap = computeAutoMaxWorkers(input.totalMemBytes, {\r\n perWorkerMemBytes,\r\n memReserveBytes,\r\n memUtilization,\r\n });\r\n\r\n if (input.configuredMaxWorkersOverride !== undefined && input.configuredMaxWorkersOverride !== null) {\r\n return {\r\n configuredMaxWorkers: positiveInt(input.configuredMaxWorkersOverride, autoCap),\r\n autoCap,\r\n workerCapSource: \"workspace_override\",\r\n };\r\n }\r\n\r\n if (config.maxConcurrentWorkers !== undefined && config.maxConcurrentWorkers !== null) {\r\n const configured = positiveInt(config.maxConcurrentWorkers, 0) || null;\r\n if (configured) {\r\n return {\r\n configuredMaxWorkers: Math.min(configured, AUTO_MAX_WORKERS_CEILING),\r\n autoCap,\r\n workerCapSource: \"config\",\r\n };\r\n }\r\n }\r\n\r\n const envIntentional =\r\n env.KYNVER_MAX_WORKERS_INTENTIONAL === \"1\" || env.KYNVER_MAX_WORKERS_INTENTIONAL === \"true\";\r\n const envCap = envIntentional && env.KYNVER_MAX_WORKERS ? positiveInt(env.KYNVER_MAX_WORKERS, 0) || null : null;\r\n if (envCap) {\r\n return {\r\n configuredMaxWorkers: Math.min(envCap, AUTO_MAX_WORKERS_CEILING),\r\n autoCap,\r\n workerCapSource: \"env\",\r\n };\r\n }\r\n\r\n return {\r\n configuredMaxWorkers: null,\r\n autoCap,\r\n workerCapSource: \"auto\",\r\n };\r\n}\r\n\r\nexport interface SetupWorkerCapRecommendation {\r\n totalMemBytes: number;\r\n autoCap: number;\r\n recommendedMaxWorkers: number;\r\n diskPath: string;\r\n diskGateOk: boolean;\r\n diskFreeBytes: number | null;\r\n}\r\n\r\n/** RAM/disk-aware default for `kynver setup` when the operator omits --max-workers. */\r\nexport function recommendSetupWorkerCap(\r\n input: {\r\n totalMemBytes?: number;\r\n diskPath?: string;\r\n diskGateOk?: boolean;\r\n diskFreeBytes?: number | null;\r\n config?: KynverUserConfig;\r\n } = {},\r\n): SetupWorkerCapRecommendation {\r\n const totalMemBytes = input.totalMemBytes ?? 0;\r\n const autoCap = computeAutoMaxWorkers(totalMemBytes, {\r\n perWorkerMemBytes: positiveInt(input.config?.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES),\r\n memReserveBytes: positiveInt(input.config?.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES),\r\n memUtilization:\r\n input.config?.memUtilization && Number(input.config.memUtilization) > 0\r\n ? Number(input.config.memUtilization)\r\n : DEFAULT_MEM_UTILIZATION,\r\n });\r\n const diskGateOk = input.diskGateOk ?? true;\r\n const recommendedMaxWorkers = diskGateOk ? autoCap : Math.max(1, Math.min(autoCap, 4));\r\n return {\r\n totalMemBytes,\r\n autoCap,\r\n recommendedMaxWorkers,\r\n diskPath: input.diskPath ?? \"/\",\r\n diskGateOk,\r\n diskFreeBytes: input.diskFreeBytes ?? null,\r\n };\r\n}\r\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\r\nimport { homedir, totalmem } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { discoverDefaultRepo } from \"./default-repo-discovery.js\";\r\nimport { displayUserPath, redactHomePath } from \"./path-values.js\";\r\nimport { trimTrailingSlash } from \"./util.js\";\r\nimport { normalizeWorkerPoolBoxKind, resolveBoxIdentity } from \"./box-identity.js\";\r\nimport { recommendSetupWorkerCap } from \"./worker-cap-source.js\";\r\nimport { observeRunnerDiskGate } from \"./disk-gate.js\";\r\nimport os from \"node:os\";\r\n\r\nexport interface KynverUserConfig {\r\n apiBaseUrl?: string;\r\n agentOsSlug?: string;\r\n agentOsId?: string;\r\n defaultRepo?: string;\r\n workerProvider?: string;\r\n /** Default Claude model when dispatch does not infer or pass `--model`. */\r\n defaultModel?: string;\r\n harnessRoot?: string;\r\n /**\r\n * Operator attestation that the hosted Kynver deployment uses this scheduler provider\r\n * (set on user runners after Vercel env cutover \u2014 scheduling is deployment-owned).\r\n */\r\n deploymentSchedulerProvider?: \"qstash\" | \"kynver-cron\" | \"openclaw-cron\";\r\n /** Physical box pool for capacity snapshots (`forge` | `ghost`). Set via `kynver setup --box-kind`. */\r\n boxKind?: \"ghost\" | \"forge\";\r\n /** Max concurrent workers on this machine. Omit to auto-size from RAM. */\r\n maxConcurrentWorkers?: number;\r\n /** Where maxConcurrentWorkers came from. */\r\n maxConcurrentWorkersSource?: \"setup-auto\" | \"setup-flag\" | \"operator\";\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n perWorkerMemBytes?: number;\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n memReserveBytes?: number;\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n memUtilization?: number;\r\n}\r\n\r\nconst CONFIG_DIR = path.join(homedir(), \".kynver\");\r\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\r\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, \"credentials\");\r\n\r\ninterface KynverCredentialsFile {\r\n apiKey?: string;\r\n /** Scoped `krc1.*` runner token for AgentOS by-id callbacks. */\r\n runnerToken?: string;\r\n runnerTokenAgentOsId?: string;\r\n}\r\n\r\nexport function loadUserConfig(): KynverUserConfig {\r\n if (!existsSync(CONFIG_FILE)) return {};\r\n try {\r\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf8\")) as KynverUserConfig;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function saveUserConfig(config: KynverUserConfig): void {\r\n mkdirSync(CONFIG_DIR, { recursive: true });\r\n writeFileSync(CONFIG_FILE, `${JSON.stringify(normalizeConfigPaths(config), null, 2)}\\n`, { mode: 0o600 });\r\n}\r\n\r\n/** Persist path fields with `~` instead of absolute home directories. */\r\nexport function normalizeConfigPaths(config: KynverUserConfig): KynverUserConfig {\r\n return {\r\n ...config,\r\n ...(config.harnessRoot?.trim() ? { harnessRoot: redactHomePath(config.harnessRoot.trim()) } : {}),\r\n ...(config.defaultRepo?.trim() ? { defaultRepo: redactHomePath(config.defaultRepo.trim()) } : {}),\r\n };\r\n}\r\n\r\n/** Values for setup output (never emit `/home/<user>/\u2026`). */\r\nexport function presentUserConfig(config: KynverUserConfig): KynverUserConfig {\r\n return normalizeConfigPaths(config);\r\n}\r\n\r\nfunction inferSetupFields(\r\n existing: KynverUserConfig,\r\n args: Record<string, string | boolean>,\r\n): Partial<KynverUserConfig> {\r\n const creds = loadCredentialsFile();\r\n const apiBaseUrl =\r\n (typeof args.apiBaseUrl === \"string\" ? args.apiBaseUrl : undefined) ||\r\n existing.apiBaseUrl?.trim() ||\r\n process.env.KYNVER_API_URL?.trim() ||\r\n process.env.KYNVER_CRON_FIRE_BASE_URL?.trim() ||\r\n process.env.OPENCLAW_CRON_FIRE_BASE_URL?.trim();\r\n const agentOsId =\r\n (typeof args.agentOsId === \"string\" ? args.agentOsId : undefined) ||\r\n existing.agentOsId?.trim() ||\r\n process.env.KYNVER_AGENT_OS_ID?.trim() ||\r\n (creds.runnerToken?.trim().startsWith(\"krc1.\") ? creds.runnerTokenAgentOsId?.trim() : undefined);\r\n const explicitRepo =\r\n typeof args.repo === \"string\"\r\n ? args.repo\r\n : args.discoverRepo === true || args.discoverRepo === \"true\"\r\n ? discoverDefaultRepo()?.repo\r\n : undefined;\r\n const defaultRepo =\r\n explicitRepo ||\r\n existing.defaultRepo?.trim() ||\r\n process.env.KYNVER_DEFAULT_REPO?.trim() ||\r\n process.env.KYNVER_HARNESS_REPO?.trim() ||\r\n discoverDefaultRepo()?.repo;\r\n const harnessRoot =\r\n (typeof args.harnessRoot === \"string\" ? args.harnessRoot : undefined) ||\r\n existing.harnessRoot?.trim() ||\r\n process.env.KYNVER_HARNESS_ROOT?.trim() ||\r\n process.env.OPUS_HARNESS_ROOT?.trim();\r\n\r\n return {\r\n ...(apiBaseUrl ? { apiBaseUrl: trimTrailingSlash(apiBaseUrl) } : {}),\r\n ...(agentOsId ? { agentOsId } : {}),\r\n ...(defaultRepo ? { defaultRepo } : {}),\r\n ...(harnessRoot ? { harnessRoot } : {}),\r\n ...(typeof args.agentOsSlug === \"string\"\r\n ? { agentOsSlug: args.agentOsSlug }\r\n : existing.agentOsSlug\r\n ? { agentOsSlug: existing.agentOsSlug }\r\n : {}),\r\n };\r\n}\r\n\r\nconst SETUP_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;\r\nconst SETUP_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;\r\nconst SETUP_MEM_UTILIZATION = 0.85;\r\nconst SETUP_AUTO_MAX_WORKERS_CEILING = 64;\r\n\r\nfunction normalizeBoxKind(raw: unknown): \"ghost\" | \"forge\" | undefined {\r\n const kind = String(raw ?? \"\").trim().toLowerCase();\r\n if (!kind) return undefined;\r\n if (kind === \"ghost\" || kind.includes(\"ghost\") || kind.includes(\"openclaw\")) return \"ghost\";\r\n if (kind === \"forge\" || kind.includes(\"forge\")) return \"forge\";\r\n return undefined;\r\n}\r\n\r\nexport function computeSetupAutoMaxWorkers(totalMemBytes: number): number {\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * SETUP_MEM_UTILIZATION) - SETUP_MEM_RESERVE_BYTES);\r\n const raw = Math.max(1, Math.floor(budgetBytes / SETUP_PER_WORKER_MEM_BYTES));\r\n return Math.min(raw, SETUP_AUTO_MAX_WORKERS_CEILING);\r\n}\r\n\r\nexport function resolveSetupWorkerConfig(\r\n existing: KynverUserConfig,\r\n args: Record<string, string | boolean>,\r\n totalMemBytes = totalmem(),\r\n): Pick<KynverUserConfig, \"maxConcurrentWorkers\" | \"maxConcurrentWorkersSource\" | \"boxKind\"> {\r\n const maxWorkersRaw =\r\n typeof args.maxWorkers === \"string\"\r\n ? args.maxWorkers\r\n : typeof args.maxConcurrentWorkers === \"string\"\r\n ? args.maxConcurrentWorkers\r\n : undefined;\r\n const explicitBoxKindArg =\r\n typeof args.boxKind === \"string\"\r\n ? args.boxKind\r\n : typeof args[\"box-kind\"] === \"string\"\r\n ? String(args[\"box-kind\"])\r\n : undefined;\r\n const boxKind = resolveBoxIdentity(process.env, {\r\n ...existing,\r\n ...(explicitBoxKindArg ? { boxKind: normalizeWorkerPoolBoxKind(explicitBoxKindArg) } : {}),\r\n }).boxKind;\r\n const diskGate = observeRunnerDiskGate({\r\n diskPath: typeof args.diskPath === \"string\" ? args.diskPath : \"/\",\r\n });\r\n const capRecommendation = recommendSetupWorkerCap({\r\n totalMemBytes,\r\n diskPath: diskGate.path,\r\n diskGateOk: diskGate.ok,\r\n diskFreeBytes: diskGate.freeBytes,\r\n config: existing,\r\n });\r\n if (maxWorkersRaw) {\r\n return {\r\n maxConcurrentWorkers: Math.max(1, Math.floor(Number(maxWorkersRaw))),\r\n maxConcurrentWorkersSource: \"setup-flag\",\r\n boxKind,\r\n };\r\n }\r\n if (existing.maxConcurrentWorkers !== undefined && existing.maxConcurrentWorkers !== null) {\r\n return {\r\n maxConcurrentWorkers: Math.max(1, Math.floor(Number(existing.maxConcurrentWorkers))),\r\n maxConcurrentWorkersSource: existing.maxConcurrentWorkersSource ?? \"operator\",\r\n boxKind,\r\n };\r\n }\r\n return {\r\n maxConcurrentWorkers: capRecommendation.recommendedMaxWorkers,\r\n maxConcurrentWorkersSource: \"setup-auto\",\r\n boxKind,\r\n };\r\n}\r\n\r\nfunction loadCredentialsFile(): KynverCredentialsFile {\r\n if (!existsSync(CREDENTIALS_FILE)) return {};\r\n try {\r\n return JSON.parse(readFileSync(CREDENTIALS_FILE, \"utf8\")) as KynverCredentialsFile;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction saveCredentialsFile(parsed: KynverCredentialsFile): void {\r\n mkdirSync(CONFIG_DIR, { recursive: true });\r\n writeFileSync(CREDENTIALS_FILE, `${JSON.stringify(parsed, null, 2)}\\n`, { mode: 0o600 });\r\n}\r\n\r\nexport function loadApiKey(): string | undefined {\r\n if (process.env.KYNVER_API_KEY) return process.env.KYNVER_API_KEY;\r\n return loadCredentialsFile().apiKey;\r\n}\r\n\r\nexport function saveApiKey(apiKey: string): void {\r\n saveCredentialsFile({ ...loadCredentialsFile(), apiKey });\r\n}\r\n\r\nexport function loadRunnerToken(agentOsId?: string): string | undefined {\r\n const envToken = process.env.KYNVER_RUNNER_TOKEN?.trim();\r\n if (envToken) return envToken;\r\n\r\n const creds = loadCredentialsFile();\r\n if (!creds.runnerToken) return undefined;\r\n if (agentOsId && creds.runnerTokenAgentOsId && creds.runnerTokenAgentOsId !== agentOsId) {\r\n return undefined;\r\n }\r\n return creds.runnerToken;\r\n}\r\n\r\nexport function saveRunnerToken(agentOsId: string, token: string): void {\r\n saveCredentialsFile({\r\n ...loadCredentialsFile(),\r\n runnerToken: token,\r\n runnerTokenAgentOsId: agentOsId,\r\n });\r\n}\r\n\r\nexport function resolveBaseUrl(argsBaseUrl?: string): string {\r\n const baseUrl = resolveConfiguredBaseUrl(argsBaseUrl);\r\n if (!baseUrl) failConfig(\"requires --base-url, KYNVER_API_URL, KYNVER_CRON_FIRE_BASE_URL, or ~/.kynver/config.json apiBaseUrl\");\r\n return baseUrl;\r\n}\r\n\r\nfunction resolveConfiguredBaseUrl(argsBaseUrl?: string): string | undefined {\r\n const baseUrl =\r\n argsBaseUrl ||\r\n process.env.KYNVER_API_URL ||\r\n process.env.KYNVER_CRON_FIRE_BASE_URL ||\r\n process.env.OPENCLAW_CRON_FIRE_BASE_URL ||\r\n loadUserConfig().apiBaseUrl;\r\n return baseUrl ? trimTrailingSlash(String(baseUrl)) : undefined;\r\n}\r\n\r\nfunction resolveConfiguredCallbackSecret(argsSecret?: string, agentOsId?: string): string | undefined {\r\n const scoped =\r\n argsSecret ||\r\n loadRunnerToken(agentOsId) ||\r\n (agentOsId ? undefined : loadRunnerToken(loadUserConfig().agentOsId));\r\n if (scoped) return String(scoped);\r\n\r\n const globalSecret =\r\n process.env.KYNVER_RUNTIME_SECRET ||\r\n process.env.KYNVER_CRON_SECRET ||\r\n process.env.OPENCLAW_CRON_SECRET;\r\n if (globalSecret) {\r\n console.warn(\r\n \"[kynver] using deployment-level callback secret; run `kynver runner credential --agent-os-id <id>` for a scoped token\",\r\n );\r\n return String(globalSecret);\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nexport function resolveCallbackSecret(argsSecret?: string, agentOsId?: string): string {\r\n const configured = resolveConfiguredCallbackSecret(argsSecret, agentOsId);\r\n if (configured) return configured;\r\n\r\n failConfig(\r\n \"requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET\",\r\n );\r\n}\r\n\r\nexport async function resolveCallbackSecretWithMint(\r\n argsSecret?: string,\r\n agentOsId?: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<string> {\r\n const configured = resolveConfiguredCallbackSecret(argsSecret, agentOsId);\r\n if (configured) return configured;\r\n\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (apiKey && agentOsId && baseUrl) {\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n saveRunnerToken(agentOsId, token);\r\n return token;\r\n } catch (error) {\r\n failConfig(`runner credential mint failed: ${(error as Error).message}`);\r\n }\r\n }\r\n\r\n failConfig(\r\n \"requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET\",\r\n );\r\n}\r\n\r\n/**\r\n * Force-mint a fresh scoped runner token for `agentOsId`, bypassing any cached\r\n * or env token. Recovery path for a callback that 401s because the configured\r\n * token is revoked, expired, or scoped to a *different* workspace (the\r\n * self-linked repair case). Requires an API key + base URL to mint; returns\r\n * `null` when a fresh token cannot be obtained, so the caller degrades to a\r\n * structural blocker instead of papering the worker over as done.\r\n */\r\nexport async function refreshRunnerToken(\r\n agentOsId: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<string | null> {\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (!apiKey || !agentOsId || !baseUrl) return null;\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n saveRunnerToken(agentOsId, token);\r\n return token;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport async function refreshRunnerTokenForAuthFailure(\r\n rejectedSecret: string,\r\n agentOsId: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<{ ok: true; token: string } | { ok: false; reason: string }> {\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (!apiKey) return { ok: false, reason: \"KYNVER_API_KEY is required to refresh a rejected runner token\" };\r\n if (!agentOsId) return { ok: false, reason: \"agentOsId is required to refresh a rejected runner token\" };\r\n if (!baseUrl) return { ok: false, reason: \"KYNVER_API_URL or --base-url is required to refresh a rejected runner token\" };\r\n\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n if (token && token !== rejectedSecret) {\r\n saveRunnerToken(agentOsId, token);\r\n return { ok: true, token };\r\n }\r\n return { ok: false, reason: \"runner credential refresh returned the rejected token\" };\r\n } catch (error) {\r\n return { ok: false, reason: (error as Error).message };\r\n }\r\n}\r\n\r\nexport async function fetchRunnerCredential(\r\n agentOsId: string,\r\n opts?: { baseUrl?: string; apiKey?: string },\r\n): Promise<string> {\r\n const apiKey = opts?.apiKey || loadApiKey();\r\n if (!apiKey) throw new Error(\"API key required \u2014 run `kynver login` first\");\r\n\r\n const base = resolveBaseUrl(opts?.baseUrl);\r\n const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/runner-credentials`;\r\n const res = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({}),\r\n });\r\n\r\n const text = await res.text();\r\n let parsed: { token?: string; error?: string } | null = null;\r\n try {\r\n parsed = JSON.parse(text) as { token?: string; error?: string };\r\n } catch {\r\n parsed = null;\r\n }\r\n if (!res.ok || !parsed?.token) {\r\n throw new Error(\r\n `runner credential mint failed (${res.status}): ${parsed?.error ?? text.slice(0, 200)}`,\r\n );\r\n }\r\n return parsed.token;\r\n}\r\n\r\nexport async function mintRunnerCredential(args: Record<string, string | boolean>): Promise<void> {\r\n const agentOsId =\r\n (args.agentOsId ? String(args.agentOsId) : loadUserConfig().agentOsId) || \"\";\r\n if (!agentOsId) failConfig(\"runner credential requires --agent-os-id or agentOsId in ~/.kynver/config.json\");\r\n\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, {\r\n baseUrl: args.baseUrl ? String(args.baseUrl) : undefined,\r\n });\r\n saveRunnerToken(agentOsId, token);\r\n console.log(\r\n JSON.stringify(\r\n {\r\n ok: true,\r\n agentOsId,\r\n credentialsPath: displayUserPath(CREDENTIALS_FILE),\r\n tokenPrefix: `${token.slice(0, 12)}\u2026`,\r\n note: \"Scoped runner token saved; callbacks use X-Kynver-Runner-Token.\",\r\n },\r\n null,\r\n 2,\r\n ),\r\n );\r\n } catch (err) {\r\n console.error(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction failConfig(message: string): never {\r\n console.error(message);\r\n process.exit(1);\r\n}\r\n\r\nexport function parseArgs(argv: string[]): Record<string, string | boolean> {\r\n const args: Record<string, string | boolean> = {};\r\n for (let i = 0; i < argv.length; i++) {\r\n const item = argv[i];\r\n if (!item.startsWith(\"--\")) continue;\r\n const key = item.slice(2).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\r\n const next = argv[i + 1];\r\n if (!next || next.startsWith(\"--\")) args[key] = true;\r\n else {\r\n args[key] = next;\r\n i++;\r\n }\r\n }\r\n return args;\r\n}\r\n\r\nexport async function runSetup(args: Record<string, string | boolean>): Promise<void> {\r\n const existing = loadUserConfig();\r\n const diskGate = observeRunnerDiskGate({\r\n diskPath: typeof args.diskPath === \"string\" ? args.diskPath : \"/\",\r\n });\r\n const capRecommendation = recommendSetupWorkerCap({\r\n totalMemBytes: os.totalmem(),\r\n diskPath: diskGate.path,\r\n diskGateOk: diskGate.ok,\r\n diskFreeBytes: diskGate.freeBytes,\r\n config: existing,\r\n });\r\n const workerConfig = resolveSetupWorkerConfig(existing, args);\r\n const config: KynverUserConfig = normalizeConfigPaths({\r\n ...existing,\r\n ...inferSetupFields(existing, args),\r\n ...workerConfig,\r\n workerProvider:\r\n typeof args.provider === \"string\"\r\n ? args.provider\r\n : existing.workerProvider || \"cursor\",\r\n });\r\n saveUserConfig(config);\r\n const boxIdentity = resolveBoxIdentity(process.env, config);\r\n\r\n let runnerCredentialNote: string | undefined;\r\n const apiKey = loadApiKey();\r\n const agentOsId = config.agentOsId;\r\n if (apiKey && agentOsId) {\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, {\r\n baseUrl: typeof args.apiBaseUrl === \"string\" ? args.apiBaseUrl : config.apiBaseUrl,\r\n apiKey,\r\n });\r\n saveRunnerToken(agentOsId, token);\r\n runnerCredentialNote = \"Scoped runner token minted and saved to ~/.kynver/credentials.\";\r\n } catch {\r\n runnerCredentialNote =\r\n \"Runner token not minted (server offline or master secret unset). Run `kynver runner credential` after deploy.\";\r\n }\r\n }\r\n\r\n console.log(\r\n JSON.stringify(\r\n {\r\n ok: true,\r\n configPath: displayUserPath(CONFIG_FILE),\r\n config: presentUserConfig(config),\r\n boxKind: config.boxKind,\r\n boxKindSource: boxIdentity.source,\r\n workerCapRecommendation: capRecommendation,\r\n ...(boxIdentity.warnings.length ? { boxIdentityWarnings: boxIdentity.warnings } : {}),\r\n note:\r\n runnerCredentialNote ??\r\n \"boxKind and maxConcurrentWorkers persisted; override with --box-kind and --max-workers. Run `kynver login` + `kynver runner credential` for scoped callbacks.\",\r\n },\r\n null,\r\n 2,\r\n ),\r\n );\r\n}\r\n\r\nexport async function runLogin(args: Record<string, string | boolean>): Promise<void> {\r\n const apiKey = typeof args.apiKey === \"string\" ? args.apiKey : process.env.KYNVER_API_KEY;\r\n if (apiKey) {\r\n saveApiKey(apiKey);\r\n console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));\r\n return;\r\n }\r\n // No key provided \u2014 run the browser \"authorize this machine\" device flow.\r\n const { runDeviceLogin } = await import(\"./device-login.js\");\r\n const result = await runDeviceLogin(args);\r\n if (!result.ok) process.exit(1);\r\n console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));\r\n}\r\n", "import { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { loadUserConfig } from \"./config.js\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\nconst LEGACY_ROOT = path.join(homedir(), \".openclaw\", \"harness\");\r\n\r\nconst HARNESS_LAYOUT_DIR_NAMES = new Set([\"runs\", \"worktrees\"]);\r\n\r\n/**\r\n * Canonical harness root: the directory that contains `runs/` and `worktrees/`.\r\n * Strips mistaken trailing layout segments (e.g. env set to `.../harness/runs`).\r\n * Server mirror: agent-os.harness-root.ts\r\n */\r\nexport function normalizeHarnessRoot(root: string): string {\r\n let resolved = path.resolve(resolveUserPath(root.trim()));\r\n while (HARNESS_LAYOUT_DIR_NAMES.has(path.basename(resolved))) {\r\n resolved = path.dirname(resolved);\r\n }\r\n return resolved;\r\n}\r\n\r\n/** Canonical harness root for CLI/workers. */\r\nexport function resolveHarnessRoot(): string {\r\n const env = process.env.KYNVER_HARNESS_ROOT || process.env.OPUS_HARNESS_ROOT;\r\n if (env) return normalizeHarnessRoot(env);\r\n const configured = loadUserConfig().harnessRoot?.trim();\r\n if (configured) return normalizeHarnessRoot(configured);\r\n const kynverRoot = path.join(homedir(), \".kynver\", \"harness\");\r\n if (existsSync(kynverRoot)) return kynverRoot;\r\n if (existsSync(LEGACY_ROOT)) return LEGACY_ROOT;\r\n return kynverRoot;\r\n}\r\n\r\nexport function harnessRunsDir(harnessRoot: string): string {\r\n return path.join(normalizeHarnessRoot(harnessRoot), \"runs\");\r\n}\r\n\r\nexport function harnessWorktreesDir(harnessRoot: string): string {\r\n return path.join(normalizeHarnessRoot(harnessRoot), \"worktrees\");\r\n}\r\n\r\nexport function getHarnessPaths() {\r\n const harnessRoot = resolveHarnessRoot();\r\n return {\r\n harnessRoot,\r\n runsDir: harnessRunsDir(harnessRoot),\r\n worktreesDir: harnessWorktreesDir(harnessRoot),\r\n };\r\n}\r\n\r\nexport function runDir(runsDir: string, id: string): string {\r\n return path.join(runsDir, safeSlug(id));\r\n}\r\n", "import path from \"node:path\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\nimport { normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport {\r\n type CleanupAction,\r\n type CleanupCandidate,\r\n type CleanupSkipReason,\r\n type HarnessCleanupOptions,\r\n type HarnessCleanupSummary,\r\n} from \"./cleanup-types.js\";\r\nimport {\r\n skipBuildCacheRemoval,\r\n skipDependencyCacheRemoval,\r\n skipWorktreeRemoval,\r\n type WorktreeGuardSkip,\r\n} from \"./cleanup-guards.js\";\r\nimport { collectPreservedLivePaths } from \"./cleanup-evidence.js\";\r\nimport {\r\n scanStaleRunDirectoryCandidates,\r\n skipRunDirectoryRemoval,\r\n} from \"./cleanup-run-directory.js\";\r\nimport {\r\n isHarnessBuildCachePath,\r\n isHarnessNextCachePath,\r\n isHarnessNodeModulesPath,\r\n removeBuildCache,\r\n removeNextCache,\r\n removeNodeModules,\r\n removeRunDirectory,\r\n removeWorktree,\r\n} from \"./cleanup-execute.js\";\r\nimport { scanBuildCacheCandidates, scanWorktreeCandidates } from \"./cleanup-scan.js\";\r\nimport { scanDependencyCacheCandidates } from \"./cleanup-dependency-scan.js\";\r\nimport { scanDuplicateWorktreeCandidates } from \"./cleanup-duplicate-worktrees.js\";\r\nimport { buildWorktreeIndexAt, type IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { finalizeStaleRuns } from \"./finalize.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport { resolveHarnessRetention, resolvePipelineHarnessRetention } from \"./cleanup-retention-config.js\";\r\nimport { assessOrphanWorktreeSafety } from \"./cleanup-orphan-safety.js\";\r\nimport { harnessStorageSnapshot } from \"./harness-storage-snapshot.js\";\r\nimport { resolveHarnessScanRoots } from \"./cleanup-harness-roots.js\";\r\nimport { collectActiveWorktreeGuards } from \"./cleanup-active-worktrees.js\";\r\nimport { applyDiskPressureToRetention, observeCleanupDiskPressure } from \"./cleanup-disk-pressure.js\";\r\nimport { emitCleanupProgress } from \"./cleanup-progress.js\";\r\nimport { CleanupGitRevCache } from \"./cleanup-git-rev-cache.js\";\r\nimport { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport { CleanupRunTerminalCache } from \"./cleanup-run-terminal-cache.js\";\r\nimport { buildCleanupCompactSummary } from \"./cleanup-summary.js\";\r\n\r\nfunction resolvePaths(options: HarnessCleanupOptions = {}) {\r\n const harnessRoot = options.harnessRoot\r\n ? normalizeHarnessRoot(options.harnessRoot)\r\n : resolveHarnessRoot();\r\n const scanRoots = resolveHarnessScanRoots({ harnessRoot });\r\n const now = options.now ?? Date.now();\r\n return { harnessRoot, scanRoots, now };\r\n}\r\n\r\nfunction normalizeGuardSkip(skip: WorktreeGuardSkip): { reason: CleanupSkipReason; detail?: string } {\r\n if (typeof skip === \"string\") return { reason: skip };\r\n return skip;\r\n}\r\n\r\nfunction recordSkip(\r\n skips: HarnessCleanupSummary[\"skips\"],\r\n pathValue: string,\r\n reason: CleanupSkipReason,\r\n detail?: string,\r\n): void {\r\n skips.push({ path: pathValue, reason, ...(detail ? { detail } : {}) });\r\n}\r\n\r\nfunction attachCandidateBytes(\r\n candidate: CleanupCandidate,\r\n accountBytes: boolean,\r\n byteEntryCap: number,\r\n): CleanupCandidate {\r\n if (!accountBytes || candidate.bytes != null) return candidate;\r\n return { ...candidate, bytes: directorySizeBytes(candidate.path, byteEntryCap) };\r\n}\r\n\r\nfunction tallySkipReasons(\r\n actions: CleanupAction[],\r\n skips: HarnessCleanupSummary[\"skips\"],\r\n): Partial<Record<CleanupSkipReason, number>> {\r\n const counts: Partial<Record<CleanupSkipReason, number>> = {};\r\n for (const skip of skips) {\r\n counts[skip.reason] = (counts[skip.reason] ?? 0) + 1;\r\n }\r\n for (const action of actions) {\r\n if (action.skipReason) {\r\n counts[action.skipReason] = (counts[action.skipReason] ?? 0) + 1;\r\n }\r\n }\r\n return counts;\r\n}\r\n\r\nfunction removeDependencyCacheAction(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n if (candidate.kind === \"remove_next_cache\") return removeNextCache(candidate, execute);\r\n return removeNodeModules(candidate, execute);\r\n}\r\n\r\nfunction pathGuardForDependencyCache(\r\n candidate: CleanupCandidate,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n if (candidate.kind === \"remove_next_cache\") {\r\n return isHarnessNextCachePath(candidate.path, harnessRoot, worktreesDir);\r\n }\r\n return isHarnessNodeModulesPath(candidate.path, harnessRoot, worktreesDir);\r\n}\r\n\r\nfunction mergeWorktreeIndexes(scanRoots: string[]): Map<string, IndexedWorktree> {\r\n const merged = new Map<string, IndexedWorktree>();\r\n for (const root of scanRoots) {\r\n for (const [key, value] of buildWorktreeIndexAt(root)) merged.set(key, value);\r\n }\r\n return merged;\r\n}\r\n\r\nfunction worktreePathForCandidate(\r\n candidate: CleanupCandidate,\r\n worktreesDir: string,\r\n): string {\r\n if (candidate.runId && candidate.worker) {\r\n return path.join(worktreesDir, candidate.runId, candidate.worker);\r\n }\r\n return path.resolve(candidate.path, \"..\");\r\n}\r\n\r\nexport function runHarnessCleanup(options: HarnessCleanupOptions = {}): HarnessCleanupSummary {\r\n let retention = resolveHarnessRetention(options);\r\n const diskPressure = observeCleanupDiskPressure();\r\n retention = applyDiskPressureToRetention(retention, diskPressure);\r\n\r\n const paths = resolvePaths(options);\r\n emitCleanupProgress(\"scan\", `${paths.scanRoots.length} harness root(s)`);\r\n const activeGuards = collectActiveWorktreeGuards(paths.scanRoots, paths.now);\r\n\r\n const finalizedRuns = retention.finalizeStaleRuns\r\n ? finalizeStaleRuns().map((f) => ({ runId: f.runId, from: f.from, to: f.to }))\r\n : [];\r\n if (finalizedRuns.length > 0) {\r\n emitCleanupProgress(\"finalize\", `${finalizedRuns.length} stale run(s) marked terminal`);\r\n }\r\n\r\n emitCleanupProgress(\"index\", \"building worktree index\");\r\n const index = mergeWorktreeIndexes(paths.scanRoots);\r\n emitCleanupProgress(\"index\", `${index.size} indexed worktree(s)`);\r\n const liveness = {\r\n runTerminalCache: new CleanupRunTerminalCache(),\r\n gitStatusCache: new CleanupGitStatusCache(),\r\n gitRevCache: new CleanupGitRevCache(),\r\n };\r\n\r\n const skips: HarnessCleanupSummary[\"skips\"] = [];\r\n const actions: CleanupAction[] = [];\r\n const processedPaths = new Set<string>();\r\n const maxActions = retention.maxActionsPerSweep;\r\n\r\n const atSweepCap = (): boolean => actions.length >= maxActions;\r\n\r\n for (const harnessRoot of paths.scanRoots) {\r\n if (atSweepCap()) break;\r\n emitCleanupProgress(\"root\", harnessRoot);\r\n const worktreesDir = path.join(harnessRoot, \"worktrees\");\r\n const scanOpts = {\r\n harnessRoot,\r\n worktreesDir,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n runIdFilter: retention.runIdFilter,\r\n index,\r\n now: paths.now,\r\n };\r\n\r\n const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);\r\n emitCleanupProgress(\"dependency\", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);\r\n let dependencyProcessed = 0;\r\n for (const raw of dependencyCandidates) {\r\n if (atSweepCap()) break;\r\n dependencyProcessed += 1;\r\n if (dependencyProcessed % 50 === 0) {\r\n emitCleanupProgress(\"dependency\", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);\r\n }\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n\r\n const pathSkip = pathGuardForDependencyCache(candidate, harnessRoot, worktreesDir);\r\n if (pathSkip) {\r\n recordSkip(skips, candidate.path, pathSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: pathSkip });\r\n continue;\r\n }\r\n const worktreePath = worktreePathForCandidate(candidate, worktreesDir);\r\n const indexed = index.get(path.resolve(worktreePath)) ?? null;\r\n const guardReason = skipDependencyCacheRemoval({\r\n indexed,\r\n includeOrphans: true,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n ageMs: candidate.ageMs,\r\n worktreePath,\r\n activeWorktreePaths: activeGuards.activeWorktreePaths,\r\n diskPressure: retention.diskPressure,\r\n gitStatusCache: liveness.gitStatusCache,\r\n });\r\n if (guardReason) {\r\n recordSkip(skips, candidate.path, guardReason);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeDependencyCacheAction(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n for (const raw of scanBuildCacheCandidates(scanOpts)) {\r\n if (atSweepCap()) break;\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n\r\n const pathSkip = isHarnessBuildCachePath(candidate.path, harnessRoot, worktreesDir);\r\n if (pathSkip) {\r\n recordSkip(skips, candidate.path, pathSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: pathSkip });\r\n continue;\r\n }\r\n const worktreePath = worktreePathForCandidate(candidate, worktreesDir);\r\n const indexed = index.get(path.resolve(worktreePath)) ?? null;\r\n const guardReason = skipBuildCacheRemoval({\r\n indexed,\r\n includeOrphans: true,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n ageMs: candidate.ageMs,\r\n worktreePath,\r\n activeWorktreePaths: activeGuards.activeWorktreePaths,\r\n diskPressure: retention.diskPressure,\r\n gitStatusCache: liveness.gitStatusCache,\r\n });\r\n if (guardReason) {\r\n recordSkip(skips, candidate.path, guardReason);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeBuildCache(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n const worktreeCandidates = [\r\n ...scanWorktreeCandidates(scanOpts),\r\n ...scanDuplicateWorktreeCandidates(scanOpts),\r\n ];\r\n emitCleanupProgress(\"worktrees\", `${worktreeCandidates.length} candidate(s) at ${harnessRoot}`);\r\n const worktreeSeen = new Set<string>();\r\n let worktreeProcessed = 0;\r\n for (const raw of worktreeCandidates) {\r\n if (atSweepCap()) break;\r\n worktreeProcessed += 1;\r\n if (worktreeProcessed % 50 === 0) {\r\n emitCleanupProgress(\"worktrees\", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);\r\n }\r\n const resolved = path.resolve(raw.path);\r\n if (worktreeSeen.has(resolved)) continue;\r\n worktreeSeen.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n const indexed = index.get(path.resolve(candidate.path)) ?? null;\r\n const orphanSafety = indexed\r\n ? null\r\n : assessOrphanWorktreeSafety({\r\n worktreePath: candidate.path,\r\n harnessRoot,\r\n runId: candidate.runId,\r\n workerName: candidate.worker,\r\n now: paths.now,\r\n });\r\n const guardSkip = skipWorktreeRemoval({\r\n indexed,\r\n worktreePath: path.resolve(candidate.path),\r\n includeOrphans: retention.includeOrphans,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n terminalWorktreesAgeMs: retention.terminalWorktreesAgeMs,\r\n ageMs: candidate.ageMs,\r\n orphanSafety,\r\n worktreeRemovalGuard: options.worktreeRemovalGuard,\r\n liveness,\r\n });\r\n if (guardSkip) {\r\n const { reason: guardReason, detail: guardDetail } = normalizeGuardSkip(guardSkip);\r\n recordSkip(skips, candidate.path, guardReason, guardDetail);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeWorktree(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n if (!atSweepCap() && retention.runDirectoriesAgeMs >= 0) {\r\n for (const raw of scanStaleRunDirectoryCandidates({\r\n harnessRoot,\r\n worktreesDir,\r\n runDirectoriesAgeMs: retention.runDirectoriesAgeMs,\r\n runIdFilter: retention.runIdFilter,\r\n activeGuards,\r\n now: paths.now,\r\n })) {\r\n if (atSweepCap()) break;\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n const runId = candidate.runId ?? path.basename(resolved);\r\n const dirSkip = skipRunDirectoryRemoval({\r\n harnessRoot,\r\n runId,\r\n runPath: resolved,\r\n ageMs: candidate.ageMs,\r\n runDirectoriesAgeMs: retention.runDirectoriesAgeMs,\r\n activeGuards,\r\n });\r\n if (dirSkip) {\r\n recordSkip(skips, candidate.path, dirSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: dirSkip });\r\n continue;\r\n }\r\n actions.push(\r\n removeRunDirectory(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n\r\n let candidateBytes = 0;\r\n let removedRunDirectories = 0;\r\n let reclaimableBytes = 0;\r\n let removedBytes = 0;\r\n let removedPaths = 0;\r\n let skippedPaths = 0;\r\n for (const action of actions) {\r\n if (action.bytes) candidateBytes += action.bytes;\r\n if (!action.skipped && !action.executed && action.bytes) reclaimableBytes += action.bytes;\r\n if (action.executed) {\r\n removedPaths += 1;\r\n removedBytes += action.bytes ?? 0;\r\n if (action.kind === \"remove_run_directory\") removedRunDirectories += 1;\r\n } else if (action.skipped) {\r\n skippedPaths += 1;\r\n if (action.skipReason === \"dry_run\" && action.bytes) reclaimableBytes += action.bytes;\r\n }\r\n }\r\n\r\n const storage = retention.accountBytes\r\n ? harnessStorageSnapshot({\r\n harnessRoot: paths.harnessRoot,\r\n now: paths.now,\r\n perRunEntryCap: retention.storagePerRunEntryCap,\r\n })\r\n : undefined;\r\n emitCleanupProgress(\r\n \"complete\",\r\n `${actions.length} action(s), ${skippedPaths} skipped, ${removedPaths} removed`,\r\n );\r\n\r\n const preservedLivePaths = collectPreservedLivePaths(actions, skips);\r\n const compactSummary = buildCleanupCompactSummary({\r\n harnessRoot: paths.harnessRoot,\r\n scanRoots: paths.scanRoots,\r\n dryRun: !retention.execute,\r\n execute: retention.execute,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n diskPressure: retention.diskPressure,\r\n diskGate: retention.diskGate\r\n ? {\r\n ok: retention.diskGate.ok,\r\n path: retention.diskGate.path,\r\n freeBytes: retention.diskGate.freeBytes,\r\n usedPercent: retention.diskGate.usedPercent,\r\n reason: retention.diskGate.reason,\r\n }\r\n : undefined,\r\n scannedAt: new Date(paths.now).toISOString(),\r\n finalizedRuns,\r\n actions,\r\n skips,\r\n totals: {\r\n candidateBytes,\r\n reclaimableBytes,\r\n removedBytes,\r\n removedPaths,\r\n skippedPaths,\r\n skipReasons: tallySkipReasons(actions, skips),\r\n },\r\n ...(storage ? { storage } : {}),\r\n ...(preservedLivePaths.length > 0 ? { preservedLivePaths } : {}),\r\n ...(removedRunDirectories > 0 ? { removedRunDirectories } : {}),\r\n });\r\n\r\n return {\r\n harnessRoot: paths.harnessRoot,\r\n scanRoots: paths.scanRoots,\r\n dryRun: !retention.execute,\r\n execute: retention.execute,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n diskPressure: retention.diskPressure,\r\n diskGate: retention.diskGate\r\n ? {\r\n ok: retention.diskGate.ok,\r\n path: retention.diskGate.path,\r\n freeBytes: retention.diskGate.freeBytes,\r\n usedPercent: retention.diskGate.usedPercent,\r\n reason: retention.diskGate.reason,\r\n }\r\n : undefined,\r\n scannedAt: new Date(paths.now).toISOString(),\r\n finalizedRuns,\r\n actions,\r\n skips,\r\n totals: {\r\n candidateBytes,\r\n reclaimableBytes,\r\n removedBytes,\r\n removedPaths,\r\n skippedPaths,\r\n skipReasons: tallySkipReasons(actions, skips),\r\n },\r\n ...(storage ? { storage } : {}),\r\n ...(preservedLivePaths.length > 0 ? { preservedLivePaths } : {}),\r\n ...(removedRunDirectories > 0 ? { removedRunDirectories } : {}),\r\n compactSummary,\r\n };\r\n}\r\n\r\n/** Pipeline-safe defaults: finalize stale runs, dry-run unless execute env is set. */\r\nexport function runPipelineHarnessCleanup(runId?: string): HarnessCleanupSummary {\r\n const retention = resolvePipelineHarnessRetention(runId);\r\n return runHarnessCleanup({\r\n execute: retention.execute,\r\n finalizeStaleRuns: retention.finalizeStaleRuns,\r\n accountBytes: retention.accountBytes,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n runIdFilter: retention.runIdFilter,\r\n });\r\n}\r\n\r\nexport function isPipelineCleanupEnabled(): boolean {\r\n return process.env.KYNVER_PIPELINE_CLEANUP !== \"0\";\r\n}\r\n", "import path from \"node:path\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupSkipReason, WorktreeRemovalGuardHook } from \"./cleanup-types.js\";\r\nimport { assessWorkerLanding } from \"./landing-gate.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport {\r\n indexedWorktreeHasMaterialChanges,\r\n resolveWorktreeGuardStatus,\r\n} from \"./cleanup-index-status.js\";\r\nimport type { CleanupRunLivenessContext } from \"./cleanup-run-liveness.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport { TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { isRunStaleActive, isWorkerProcessLive, runBlocksWorktreeRemoval } from \"./cleanup-run-liveness.js\";\r\nimport { completionBlockerBlocksWorktreeRemoval } from \"./cleanup-completion-blocker.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport {\r\n isLandedGitAncestry,\r\n isPrOrUnmergedWork,\r\n prUrlFromFinalResult,\r\n} from \"./cleanup-worktree-salvage.js\";\r\n\r\nexport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nexport { isLandedGitAncestry, isPrOrUnmergedWork } from \"./cleanup-worktree-salvage.js\";\r\n\r\nexport interface WorktreeGuardInput {\r\n indexed: IndexedWorktree | null;\r\n /** Resolved worktree directory (required for overlay guards on orphans). */\r\n worktreePath: string;\r\n includeOrphans: boolean;\r\n worktreesAgeMs: number;\r\n /** Shorter age gate for harness runs already marked terminal. */\r\n terminalWorktreesAgeMs: number;\r\n ageMs: number;\r\n /**\r\n * Filesystem-derived skip reason for orphan candidates (computed by\r\n * `assessOrphanWorktreeSafety`). Used only when `indexed` is null.\r\n */\r\n orphanSafety?: CleanupSkipReason | null;\r\n worktreeRemovalGuard?: WorktreeRemovalGuardHook;\r\n liveness?: CleanupRunLivenessContext;\r\n}\r\n\r\nexport type WorktreeGuardSkip = CleanupSkipReason | { reason: CleanupSkipReason; detail?: string };\r\n\r\nfunction effectiveWorktreeAgeMs(input: WorktreeGuardInput): number {\r\n const { indexed, includeOrphans, worktreesAgeMs, terminalWorktreesAgeMs } = input;\r\n if (!indexed) return includeOrphans ? terminalWorktreesAgeMs : worktreesAgeMs;\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n if (input.liveness && isRunStaleActive(indexed, input.liveness)) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n if (\r\n input.liveness &&\r\n isFinishedWorkerStatus(resolveWorktreeGuardStatus(indexed, input.liveness)) &&\r\n !isWorkerProcessLive(indexed)\r\n ) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n return worktreesAgeMs;\r\n}\r\n\r\nexport function skipWorktreeRemoval(input: WorktreeGuardInput): WorktreeGuardSkip | null {\r\n const { indexed, includeOrphans, worktreesAgeMs, ageMs, orphanSafety, worktreeRemovalGuard } =\r\n input;\r\n if (!indexed) {\r\n if (!includeOrphans) return \"orphan_without_flag\";\r\n return orphanSafety ?? null;\r\n }\r\n // `--include-orphans` is the operator opt-in for aggressive cleanup; trust\r\n // the indexed salvage gates below (active_worker, pr_or_unmerged_commits,\r\n // dirty_worktree, landing_blocked) instead of the age-only short-circuit.\r\n const ageThresholdMs = effectiveWorktreeAgeMs(input);\r\n if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return \"worktrees_disabled\";\r\n if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return \"below_age_threshold\";\r\n if (isWorkerProcessLive(indexed)) return \"active_worker\";\r\n if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {\r\n return \"dirty_worktree\";\r\n }\r\n const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);\r\n if (ahead !== null && ahead !== undefined && ahead > 0) return \"pr_or_unmerged_commits\";\r\n const status = resolveWorktreeGuardStatus(indexed, input.liveness);\r\n if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return \"completion_blocked\";\r\n if (runBlocksWorktreeRemoval(indexed, input.liveness)) return \"run_still_active\";\r\n if (!isFinishedWorkerStatus(status)) return \"run_still_active\";\r\n if (isPrOrUnmergedWork(status)) return \"pr_or_unmerged_commits\";\r\n if (materialWorktreeChanges(status.changedFiles).length > 0) return \"dirty_worktree\";\r\n const landing = assessWorkerLanding({\r\n finalResult: status.finalResult,\r\n changedFiles: status.changedFiles,\r\n gitAncestry: status.gitAncestry,\r\n prUrl: prUrlFromFinalResult(status.finalResult),\r\n });\r\n if (landing.blocked) return \"landing_blocked\";\r\n if (worktreeRemovalGuard && input.worktreePath) {\r\n const overlay = worktreeRemovalGuard({\r\n worktreePath: input.worktreePath,\r\n indexed: Boolean(indexed),\r\n runId: indexed?.runId,\r\n worker: indexed?.workerName,\r\n });\r\n if (overlay) {\r\n return overlay.detail ? { reason: overlay.reason, detail: overlay.detail } : overlay.reason;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nexport interface NodeModulesGuardInput {\r\n indexed: IndexedWorktree | null;\r\n includeOrphans: boolean;\r\n nodeModulesAgeMs: number;\r\n ageMs: number;\r\n}\r\n\r\nexport interface DependencyCacheGuardInput extends NodeModulesGuardInput {\r\n worktreePath: string;\r\n activeWorktreePaths: Set<string>;\r\n diskPressure?: boolean;\r\n gitStatusCache?: CleanupGitStatusCache;\r\n}\r\n\r\n/**\r\n * Dependency caches (`node_modules`, `.next`) are safe to drop when the worker\r\n * process is dead and source files remain \u2014 even if the board still shows\r\n * completion/landing/PR blockers. Whole-worktree removal stays strict.\r\n */\r\nexport function skipDependencyCacheRemoval(input: DependencyCacheGuardInput): CleanupSkipReason | null {\r\n const { indexed, nodeModulesAgeMs, ageMs, worktreePath, activeWorktreePaths, diskPressure } =\r\n input;\r\n if (!diskPressure && ageMs < nodeModulesAgeMs) return \"below_age_threshold\";\r\n if (activeWorktreePaths.has(path.resolve(worktreePath))) return \"active_worker\";\r\n if (indexed && isWorkerProcessLive(indexed)) return \"active_worker\";\r\n if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {\r\n return \"dirty_worktree\";\r\n }\r\n return null;\r\n}\r\n\r\n/** Build caches (`.turbo`, `dist`, etc.) use the same relaxed guards as dependency caches. */\r\nexport function skipBuildCacheRemoval(input: DependencyCacheGuardInput): CleanupSkipReason | null {\r\n return skipDependencyCacheRemoval(input);\r\n}\r\n\r\nexport function skipNodeModulesRemoval(input: NodeModulesGuardInput): CleanupSkipReason | null {\r\n return skipDependencyCacheRemoval({\r\n ...input,\r\n worktreePath: input.indexed?.worktreePath ?? \"\",\r\n activeWorktreePaths: new Set(),\r\n diskPressure: false,\r\n });\r\n}\r\n", "import { computeGitAncestry, gitStatusShort } from \"./git.js\";\r\nimport { computeWorkerStatus, type RawHarnessWorkerStatus } from \"./status.js\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupRunLivenessContext } from \"./cleanup-run-liveness.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { prUrlFromFinalResult } from \"./cleanup-worktree-salvage.js\";\r\nimport { isPidAlive } from \"./util.js\";\r\n\r\n/** Lazily compute worker status \u2014 avoids git/stream work for every indexed worker up front. */\r\nexport function indexedWorktreeStatus(entry: IndexedWorktree): RawHarnessWorkerStatus {\r\n if (!entry.status) {\r\n entry.status = computeWorkerStatus(entry.worker, {\r\n base: entry.run.base,\r\n baseCommit: entry.run.baseCommit,\r\n });\r\n }\r\n return entry.status;\r\n}\r\n\r\n/**\r\n * Porcelain-only dirty probe for dependency-cache guards. Skips ancestry/stream\r\n * work that whole-worktree removal needs but `node_modules` GC does not.\r\n */\r\nexport function indexedWorktreeHasMaterialChanges(\r\n entry: IndexedWorktree,\r\n gitStatusCache?: CleanupGitStatusCache,\r\n): boolean {\r\n if (entry.status) {\r\n return materialWorktreeChanges(entry.status.changedFiles).length > 0;\r\n }\r\n const porcelain = gitStatusCache\r\n ? gitStatusCache.porcelain(entry.worktreePath)\r\n : gitStatusShort(entry.worktreePath);\r\n return materialWorktreeChanges(porcelain).length > 0;\r\n}\r\n\r\nfunction finalResultFromWorkerJson(entry: IndexedWorktree): unknown {\r\n const snapshot = entry.worker.completionSnapshot?.finalResult;\r\n if (snapshot !== undefined && snapshot !== null) return snapshot;\r\n if (entry.worker.taskPrUrl) {\r\n return { prUrl: entry.worker.taskPrUrl };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Guard-oriented status: avoids stdout/heartbeat stream parsing for terminal workers\r\n * while preserving salvage semantics (dirty / PR / landing checks).\r\n */\r\nexport function resolveWorktreeGuardStatus(\r\n entry: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): RawHarnessWorkerStatus {\r\n if (entry.status) return entry.status;\r\n\r\n const worker = entry.worker;\r\n const completionAcknowledged =\r\n typeof worker.completionReportedAt === \"string\" && worker.completionReportedAt.trim().length > 0;\r\n const workerJsonTerminal =\r\n Boolean(worker.status && [\"done\", \"exited\", \"blocked\", \"failed\", \"abandoned\"].includes(worker.status)) ||\r\n completionAcknowledged;\r\n const finalResult = finalResultFromWorkerJson(entry);\r\n\r\n if (workerJsonTerminal && !isPidAlive(worker.pid)) {\r\n const changedFiles = ctx?.gitStatusCache\r\n ? ctx.gitStatusCache.porcelain(entry.worktreePath)\r\n : gitStatusShort(entry.worktreePath);\r\n const baseLabel = entry.run.baseCommit?.trim() || entry.run.base?.trim() || \"origin/main\";\r\n const ahead = ctx?.gitRevCache?.countAheadOfMain(entry.worktreePath, baseLabel);\r\n const gitAncestry =\r\n ahead === 0\r\n ? {\r\n checked: true,\r\n base: baseLabel,\r\n relation: \"synced\" as const,\r\n }\r\n : computeGitAncestry(entry.worktreePath, {\r\n base: entry.run.base,\r\n baseCommit: entry.run.baseCommit,\r\n });\r\n const status = {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n pid: worker.pid,\r\n alive: false,\r\n status: worker.status ?? (completionAcknowledged ? \"done\" : \"exited\"),\r\n attention: { state: completionAcknowledged ? \"done\" : \"stale\" },\r\n branch: worker.branch,\r\n worktreePath: entry.worktreePath,\r\n ownedPaths: worker.ownedPaths,\r\n stdoutBytes: 0,\r\n stderrBytes: 0,\r\n heartbeatBytes: 0,\r\n firstEventAt: null,\r\n lastEventAt: null,\r\n lastActivityAt: worker.completionReportedAt ?? null,\r\n currentTool: null,\r\n heartbeatCount: 0,\r\n lastHeartbeatAt: null,\r\n lastHeartbeatPhase: null,\r\n lastHeartbeatSummary: null,\r\n heartbeatBlocker: null,\r\n changedFiles,\r\n gitAncestry,\r\n finalResult,\r\n completionBlocker:\r\n typeof worker.completionBlocker === \"string\" ? worker.completionBlocker.trim() || null : null,\r\n prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? prUrlFromFinalResult(finalResult),\r\n } as unknown as RawHarnessWorkerStatus;\r\n entry.status = status;\r\n return status;\r\n }\r\n\r\n return indexedWorktreeStatus(entry);\r\n}\r\n", "/** Generated install/build trees safe to delete under a harness worktree. */\r\nexport const HARNESS_BUILD_CACHE_RELATIVE_PATHS = [\r\n \".next\",\r\n \".turbo\",\r\n \"dist\",\r\n \"build\",\r\n \".cache\",\r\n \"node_modules/.cache\",\r\n] as const;\r\n\r\nexport type HarnessBuildCacheRelativePath = (typeof HARNESS_BUILD_CACHE_RELATIVE_PATHS)[number];\r\n\r\n/** True when a porcelain path is only generated build/install noise. */\r\nexport function isGeneratedHarnessPath(pathPart: string): boolean {\r\n const normalized = pathPart.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\r\n if (normalized === \"node_modules\" || normalized.startsWith(\"node_modules/\")) return true;\r\n for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {\r\n if (normalized === rel || normalized.startsWith(`${rel}/`)) return true;\r\n }\r\n return false;\r\n}\r\n", "import { isGeneratedHarnessPath } from \"./cleanup-build-cache-paths.js\";\r\n\r\n/** Strip generated install/build trees from porcelain \u2014 they are what cleanup removes. */\r\nexport function materialWorktreeChanges(changedFiles: string[]): string[] {\r\n return changedFiles.filter((line) => {\r\n const trimmed = line.trim();\r\n const pathPart = trimmed.startsWith(\"??\")\r\n ? trimmed.slice(2).trim()\r\n : trimmed.length > 3\r\n ? trimmed.slice(3).trim()\r\n : trimmed;\r\n return !isGeneratedHarnessPath(pathPart);\r\n });\r\n}\r\n", "import type { GitAncestry } from \"./git.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\n\r\nexport function prUrlFromFinalResult(finalResult: unknown): string | null {\r\n if (typeof finalResult === \"string\") {\r\n const match = finalResult.match(/https:\\/\\/github\\.com\\/[^\\s]+\\/pull\\/\\d+/i);\r\n return match?.[0] ?? null;\r\n }\r\n if (finalResult && typeof finalResult === \"object\") {\r\n const obj = finalResult as Record<string, unknown>;\r\n for (const key of [\"prUrl\", \"pr_url\", \"pullRequestUrl\"]) {\r\n const value = obj[key];\r\n if (typeof value === \"string\" && value.trim()) return value.trim();\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/** True when git ancestry shows the worker branch is fully landed on the run base. */\r\nexport function isLandedGitAncestry(ancestry: GitAncestry | null | undefined): boolean {\r\n const relation = ancestry?.relation;\r\n return relation === \"merged\" || relation === \"synced\";\r\n}\r\n\r\n/** Blocks whole-worktree removal when commits are not landed or tree is dirty. */\r\nexport function isPrOrUnmergedWork(status: RawHarnessWorkerStatus): boolean {\r\n const relation = status.gitAncestry?.relation;\r\n if (relation === \"merged\" || relation === \"synced\") {\r\n return materialWorktreeChanges(status.changedFiles).length > 0;\r\n }\r\n if (prUrlFromFinalResult(status.finalResult)) return true;\r\n if (relation === \"ahead\" || relation === \"diverged\") return true;\r\n if (status.changedFiles.length > 0 && status.finalResult) return true;\r\n return false;\r\n}\r\n", "import path from \"node:path\";\r\nimport { listRunRecords, runDirectory, saveRun, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { listRunWorkerNames } from \"./run-worker-index.js\";\r\nimport { computeWorkerStatus, isLandingBlockedWorkerStatus } from \"./status.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport interface RunFinalizeResult {\r\n runId: string;\r\n from: string;\r\n to: string;\r\n}\r\n\r\n/** Run statuses we treat as \"not yet terminal\" and therefore candidates for finalization. */\r\nexport const ACTIVE_RUN_STATUSES = new Set([\r\n \"running\",\r\n \"dispatching\",\r\n \"pending\",\r\n \"queued\",\r\n \"needs_attention\",\r\n]);\r\n\r\nexport const TERMINAL_RUN_STATUSES = new Set([\"completed\", \"failed\", \"cancelled\", \"done\"]);\r\n\r\n/**\r\n * Decide the terminal status for a run, or null if it should stay active.\r\n * A run is terminal once none of its workers are still alive-and-unfinished.\r\n */\r\nexport function deriveTerminalRunStatus(run: HarnessRunRecord): string | null {\r\n const names = listRunWorkerNames(run);\r\n if (names.length === 0) return \"failed\"; // marked active but never started a worker\r\n let anyAlive = false;\r\n let anyResult = false;\r\n let anyCompletionBlocked = false;\r\n let anyLandingBlocked = false;\r\n for (const name of names) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectory(run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker) continue;\r\n const status = computeWorkerStatus(worker, {\r\n base: run.base,\r\n baseCommit: run.baseCommit,\r\n });\r\n if (status.alive && !status.finalResult) {\r\n anyAlive = true;\r\n break;\r\n }\r\n // A finished worker whose AgentOS completion replay was rejected (e.g. a\r\n // revoked / expired / cross-workspace runner token) is NOT done: its linked\r\n // AgentTask never advanced. Keep the run non-terminal so the pipeline keeps\r\n // retrying completion (and the board surfaces the blocked worker) instead of\r\n // papering an invalid runner token over as `completed`.\r\n if (typeof worker.completionBlocker === \"string\" && worker.completionBlocker) {\r\n anyCompletionBlocked = true;\r\n }\r\n if (isLandingBlockedWorkerStatus(status)) {\r\n anyLandingBlocked = true;\r\n }\r\n if (status.finalResult && status.attention.state === \"done\") anyResult = true;\r\n }\r\n if (anyAlive) return null; // still doing real work \u2014 leave it running\r\n if (anyCompletionBlocked) return null; // completion replay blocked \u2014 not yet terminal\r\n if (anyLandingBlocked) return null; // dirty/unlanded work \u2014 keep run active for operator attention\r\n return anyResult ? \"completed\" : \"failed\";\r\n}\r\n\r\n/**\r\n * Finalize runs that are still marked active but have no live workers.\r\n *\r\n * The harness creates one run per task and never closed them out, leaving dozens\r\n * of \"running\" runs that bloated disk and broke operator views (and made cleanup\r\n * unsafe to reason about). Active-worker accounting already excludes dead workers,\r\n * so this is about run-status hygiene + enabling safe pruning of finished runs.\r\n *\r\n * Returns the runs whose status changed.\r\n */\r\nexport function finalizeStaleRuns(): RunFinalizeResult[] {\r\n const finalized: RunFinalizeResult[] = [];\r\n for (const run of listRunRecords()) {\r\n if (!ACTIVE_RUN_STATUSES.has(run.status)) continue;\r\n const next = deriveTerminalRunStatus(run);\r\n if (!next || next === run.status) continue;\r\n const from = run.status;\r\n run.status = next;\r\n saveRun(run);\r\n finalized.push({ runId: run.id, from, to: next });\r\n }\r\n return finalized;\r\n}\r\n", "import { deriveTerminalRunStatus, TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { indexedWorktreeStatus } from \"./cleanup-index-status.js\";\r\nimport type { CleanupGitRevCache } from \"./cleanup-git-rev-cache.js\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupRunTerminalCache } from \"./cleanup-run-terminal-cache.js\";\r\nimport { completionBlockerBlocksWorktreeRemoval } from \"./cleanup-completion-blocker.js\";\r\nimport { isPidAlive } from \"./util.js\";\r\n\r\nconst TERMINAL_WORKER_JSON_STATUSES = new Set([\r\n \"done\",\r\n \"exited\",\r\n \"blocked\",\r\n \"failed\",\r\n \"abandoned\",\r\n]);\r\n\r\nexport interface CleanupRunLivenessContext {\r\n runTerminalCache: CleanupRunTerminalCache;\r\n gitStatusCache: CleanupGitStatusCache;\r\n gitRevCache: CleanupGitRevCache;\r\n}\r\n\r\nfunction deriveRunTerminal(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): string | null {\r\n if (ctx) return ctx.runTerminalCache.derive(indexed.run);\r\n return deriveTerminalRunStatus(indexed.run);\r\n}\r\n\r\n/**\r\n * True when the worker process is still live. Broad cleanup scans use worker.json\r\n * terminal hints before falling back to full `computeWorkerStatus` (expensive).\r\n */\r\nexport function isWorkerProcessLive(indexed: IndexedWorktree): boolean {\r\n if (isPidAlive(indexed.worker.pid)) return true;\r\n if (\r\n typeof indexed.worker.completionReportedAt === \"string\" &&\r\n indexed.worker.completionReportedAt.trim().length > 0\r\n ) {\r\n return false;\r\n }\r\n const workerStatus = indexed.worker.status;\r\n if (workerStatus && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus)) return false;\r\n if (!indexed.worker.pid) {\r\n if (workerStatus !== \"running\") return false;\r\n return indexedWorktreeStatus(indexed).alive;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Run record still marked active but every worker is finished \u2014 safe to treat as\r\n * terminal for GC after `finalizeStaleRuns()` (or when deriveTerminalRunStatus is set).\r\n */\r\nexport function isRunStaleActive(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): boolean {\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;\r\n return deriveRunTerminal(indexed, ctx) !== null;\r\n}\r\n\r\n/**\r\n * Whether the harness run still has unfinished work that should block whole-worktree removal.\r\n * Does not block per-worker `node_modules` when only this worker is finished.\r\n */\r\nexport function runBlocksWorktreeRemoval(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): boolean {\r\n if (isWorkerProcessLive(indexed)) return true;\r\n const workerStatus = indexed.worker.status;\r\n if (\r\n workerStatus &&\r\n TERMINAL_WORKER_JSON_STATUSES.has(workerStatus) &&\r\n !indexed.worker.completionBlocker\r\n ) {\r\n return false;\r\n }\r\n const status = indexedWorktreeStatus(indexed);\r\n if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;\r\n // Finished dead workers are not held back by run-level bookkeeping (siblings, stale run.json).\r\n if (isFinishedWorkerStatus(status)) return false;\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;\r\n if (isRunStaleActive(indexed, ctx)) return false;\r\n return deriveRunTerminal(indexed, ctx) === null;\r\n}\r\n", "import { assessWorkerLanding } from \"./landing-gate.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { indexedWorktreeStatus } from \"./cleanup-index-status.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport { isWorkerProcessLive } from \"./cleanup-run-liveness.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport { isPrOrUnmergedWork, prUrlFromFinalResult } from \"./cleanup-worktree-salvage.js\";\r\n\r\n/**\r\n * Whether a persisted `completionBlocker` should still block whole-worktree removal.\r\n *\r\n * Dead workers with landed/clean work may keep replay metadata on disk after the\r\n * board advanced externally \u2014 those blockers are stale for GC and must not pin\r\n * worktrees indefinitely.\r\n */\r\nexport function completionBlockerBlocksWorktreeRemoval(\r\n indexed: IndexedWorktree,\r\n status?: RawHarnessWorkerStatus,\r\n): boolean {\r\n const blocker =\r\n typeof indexed.worker.completionBlocker === \"string\" ? indexed.worker.completionBlocker.trim() : \"\";\r\n if (!blocker) return false;\r\n if (isWorkerProcessLive(indexed)) return true;\r\n\r\n const resolved = status ?? indexedWorktreeStatus(indexed);\r\n if (!isFinishedWorkerStatus(resolved)) return true;\r\n if (isPrOrUnmergedWork(resolved)) return true;\r\n if (materialWorktreeChanges(resolved.changedFiles).length > 0) return true;\r\n\r\n const landing = assessWorkerLanding({\r\n finalResult: resolved.finalResult,\r\n changedFiles: resolved.changedFiles,\r\n gitAncestry: resolved.gitAncestry,\r\n prUrl: prUrlFromFinalResult(resolved.finalResult),\r\n });\r\n if (landing.blocked) return true;\r\n\r\n return false;\r\n}\r\n", "export type CleanupActionKind =\r\n | \"remove_node_modules\"\r\n | \"remove_next_cache\"\r\n | \"remove_build_cache\"\r\n | \"remove_worktree\"\r\n | \"remove_run_directory\";\r\n\r\nexport type CleanupSkipReason =\r\n | \"dry_run\"\r\n | \"below_age_threshold\"\r\n | \"active_worker\"\r\n | \"dirty_worktree\"\r\n | \"landing_blocked\"\r\n | \"pr_or_unmerged_commits\"\r\n | \"completion_blocked\"\r\n | \"run_still_active\"\r\n | \"path_outside_harness\"\r\n | \"worktrees_disabled\"\r\n | \"orphan_without_flag\"\r\n | \"missing_worktree\"\r\n | \"remove_failed\"\r\n /** Generated cache owned by another user (often root); daemon cannot unlink without privileged reclaim. */\r\n | \"foreign_owner\"\r\n /** Harness `runs/` metadata must never be removed by worktree GC. */\r\n | \"run_metadata_protected\"\r\n /** AgentOS / operator lifecycle overlay blocked removal (see `detail`). */\r\n | \"board_lifecycle_blocked\";\r\n\r\nexport interface CleanupCandidate {\r\n kind: CleanupActionKind;\r\n path: string;\r\n bytes: number | null;\r\n harnessRoot?: string;\r\n runId?: string;\r\n worker?: string;\r\n repo?: string;\r\n ageMs: number;\r\n}\r\n\r\nexport interface CleanupAction extends CleanupCandidate {\r\n executed: boolean;\r\n skipped: boolean;\r\n skipReason?: CleanupSkipReason;\r\n error?: string;\r\n}\r\n\r\nexport interface RunFinalizeSummary {\r\n runId: string;\r\n from: string;\r\n to: string;\r\n}\r\n\r\nexport interface HarnessStorageSnapshotShape {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n worktreesBytes: number | null;\r\n runCount: number;\r\n workerCount: number;\r\n oldestRunAt: string | null;\r\n scannedAt: string;\r\n}\r\n\r\nexport interface HarnessCleanupSummary {\r\n harnessRoot: string;\r\n /** Every harness tree scanned (primary + well-known extras). */\r\n scanRoots: string[];\r\n dryRun: boolean;\r\n execute: boolean;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n includeOrphans: boolean;\r\n diskPressure?: boolean;\r\n diskGate?: {\r\n ok: boolean;\r\n path: string;\r\n freeBytes: number;\r\n usedPercent: number;\r\n reason: string | null;\r\n };\r\n scannedAt: string;\r\n finalizedRuns: RunFinalizeSummary[];\r\n actions: CleanupAction[];\r\n skips: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>;\r\n totals: {\r\n candidateBytes: number;\r\n reclaimableBytes: number;\r\n removedBytes: number;\r\n removedPaths: number;\r\n skippedPaths: number;\r\n skipReasons: Partial<Record<CleanupSkipReason, number>>;\r\n };\r\n /** Disk-pressure evidence \u2014 present when bytes accounting is enabled. */\r\n storage?: HarnessStorageSnapshotShape;\r\n /** Sample of paths kept because workers/runs are still live (for operator summaries). */\r\n preservedLivePaths?: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>;\r\n /** Empty harness worktree run directories removed after worker worktrees were reclaimed. */\r\n removedRunDirectories?: number;\r\n /** Bounded operator rollup (always attached; use `kynver cleanup --compact` to emit alone). */\r\n compactSummary?: import(\"./cleanup-summary.js\").CleanupCompactSummary;\r\n}\r\n\r\nexport interface WorktreeRemovalGuardInput {\r\n worktreePath: string;\r\n /** True when `buildWorktreeIndex()` has a worker.json entry for this path. */\r\n indexed: boolean;\r\n runId?: string;\r\n worker?: string;\r\n}\r\n\r\n/** Optional overlay (e.g. AgentOS board + lease checks) evaluated after runtime salvage gates. */\r\nexport type WorktreeRemovalGuardHook = (\r\n input: WorktreeRemovalGuardInput,\r\n) => { reason: CleanupSkipReason; detail?: string } | null;\r\n\r\nexport interface HarnessCleanupOptions {\r\n harnessRoot?: string;\r\n /** When false (default), only report candidates. */\r\n execute?: boolean;\r\n /** When true (default), call `finalizeStaleRuns()` before scanning. */\r\n finalizeStaleRuns?: boolean;\r\n /** When true, estimate candidate bytes for guard-passing removals only. CLI defaults false. */\r\n accountBytes?: boolean;\r\n /** Per-run entry cap for storage snapshot byte totals (`0` = counts only). */\r\n storagePerRunEntryCap?: number | null;\r\n /** Per-candidate filesystem walk cap when `du` is unavailable. */\r\n byteAccountingEntryCap?: number;\r\n /** Minimum age before removing generated `node_modules` (default 6h). */\r\n nodeModulesAgeMs?: number;\r\n /** When 0 or unset, worktree removal is disabled. */\r\n worktreesAgeMs?: number;\r\n /**\r\n * Age threshold for worktrees whose harness run is already terminal\r\n * (`completed` / `failed` / `cancelled` / `done`). Salvage gates still apply.\r\n */\r\n terminalWorktreesAgeMs?: number;\r\n /** Minimum age before removing an empty `worktrees/<runId>/` directory. */\r\n runDirectoriesAgeMs?: number;\r\n /** Cap actions evaluated per sweep (cron/watchdog boundedness). */\r\n maxActionsPerSweep?: number;\r\n /** Allow cleaning `node_modules` under worktrees with no worker index entry. */\r\n includeOrphans?: boolean;\r\n /** When set, only consider workers for this harness run (pipeline tick scope). */\r\n runIdFilter?: string;\r\n now?: number;\r\n /** When set, invoked for each worktree candidate after built-in salvage guards. */\r\n worktreeRemovalGuard?: WorktreeRemovalGuardHook;\r\n}\r\n\r\n/** Conservative default aligned with 2026-05-27 manual harness cleanup (6h). */\r\nexport const DEFAULT_NODE_MODULES_AGE_MS = 6 * 60 * 60 * 1000;\r\n\r\n/** Seven days \u2014 only used when worktree cleanup is explicitly enabled. */\r\nexport const DEFAULT_WORKTREES_AGE_MS = 7 * 24 * 60 * 60 * 1000;\r\n\r\n/** Terminal runs: salvage-first worktree removal after workers finish (6h default). */\r\nexport const DEFAULT_TERMINAL_WORKTREES_AGE_MS = DEFAULT_NODE_MODULES_AGE_MS;\r\n\r\n/** Empty per-run worktree folders under `worktrees/<runId>/`. */\r\nexport const DEFAULT_RUN_DIRECTORIES_AGE_MS = 60 * 60 * 1000;\r\n\r\n/** Bounded cron/watchdog scan \u2014 skip remaining candidates when exceeded. */\r\nexport const DEFAULT_MAX_ACTIONS_PER_SWEEP = 120;\r\n\r\nexport const MAX_PRESERVED_LIVE_PATH_SAMPLES = 24;\r\n", "import type { CleanupAction, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport { MAX_PRESERVED_LIVE_PATH_SAMPLES } from \"./cleanup-types.js\";\r\n\r\nconst LIVE_SKIP_REASONS = new Set<CleanupSkipReason>([\r\n \"active_worker\",\r\n \"run_still_active\",\r\n \"completion_blocked\",\r\n \"landing_blocked\",\r\n]);\r\n\r\nexport function collectPreservedLivePaths(\r\n actions: CleanupAction[],\r\n skips: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>,\r\n): Array<{ path: string; reason: CleanupSkipReason; detail?: string }> {\r\n const out: Array<{ path: string; reason: CleanupSkipReason; detail?: string }> = [];\r\n const seen = new Set<string>();\r\n\r\n const push = (path: string, reason: CleanupSkipReason, detail?: string) => {\r\n const key = `${path}\\0${reason}`;\r\n if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;\r\n seen.add(key);\r\n out.push({ path, reason, ...(detail ? { detail } : {}) });\r\n };\r\n\r\n for (const skip of skips) {\r\n if (!LIVE_SKIP_REASONS.has(skip.reason)) continue;\r\n push(skip.path, skip.reason, skip.detail);\r\n }\r\n for (const action of actions) {\r\n if (!action.skipped || !action.skipReason) continue;\r\n if (!LIVE_SKIP_REASONS.has(action.skipReason)) continue;\r\n push(action.path, action.skipReason);\r\n }\r\n\r\n return out;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport type { ActiveWorktreeGuardSnapshot } from \"./cleanup-active-worktrees.js\";\r\nimport { isWorktreeOnLiveRun } from \"./cleanup-active-worktrees.js\";\r\nimport { deriveTerminalRunStatus, TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { readJson } from \"./util.js\";\r\nimport type { HarnessRunRecord } from \"./run-store.js\";\r\n\r\nexport interface ScanRunDirectoryOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n runDirectoriesAgeMs: number;\r\n runIdFilter?: string;\r\n activeGuards: ActiveWorktreeGuardSnapshot;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction loadRunStatus(harnessRoot: string, runId: string): HarnessRunRecord | null {\r\n const runPath = path.join(harnessRoot, \"runs\", runId, \"run.json\");\r\n if (!existsSync(runPath)) return null;\r\n return readJson<HarnessRunRecord | null>(runPath, null);\r\n}\r\n\r\nfunction runDirectoryIsEmpty(runPath: string): boolean {\r\n try {\r\n const entries = readdirSync(runPath);\r\n return entries.length === 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function skipRunDirectoryRemoval(input: {\r\n harnessRoot: string;\r\n runId: string;\r\n runPath: string;\r\n ageMs: number;\r\n runDirectoriesAgeMs: number;\r\n activeGuards: ActiveWorktreeGuardSnapshot;\r\n}): CleanupSkipReason | null {\r\n const { harnessRoot, runId, runPath, ageMs, runDirectoriesAgeMs, activeGuards } = input;\r\n if (isWorktreeOnLiveRun(runPath, harnessRoot, runId, activeGuards.liveRunKeys)) {\r\n return \"run_still_active\";\r\n }\r\n if (!runDirectoryIsEmpty(runPath)) return \"run_still_active\";\r\n const run = loadRunStatus(harnessRoot, runId);\r\n if (run && !TERMINAL_RUN_STATUSES.has(run.status)) {\r\n if (!deriveTerminalRunStatus(run)) return \"run_still_active\";\r\n }\r\n if (runDirectoriesAgeMs > 0 && ageMs < runDirectoriesAgeMs) return \"below_age_threshold\";\r\n return null;\r\n}\r\n\r\n/** Empty per-run folders under `worktrees/<runId>/` after worker worktrees are gone. */\r\nexport function scanStaleRunDirectoryCandidates(\r\n opts: ScanRunDirectoryOptions,\r\n): CleanupCandidate[] {\r\n if (!existsSync(opts.worktreesDir)) return [];\r\n const candidates: CleanupCandidate[] = [];\r\n let entries;\r\n try {\r\n entries = readdirSync(opts.worktreesDir, { withFileTypes: true });\r\n } catch {\r\n return [];\r\n }\r\n\r\n for (const runEntry of entries) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runId = runEntry.name;\r\n if (opts.runIdFilter && runId !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runId);\r\n if (!runDirectoryIsEmpty(runPath)) continue;\r\n candidates.push({\r\n kind: \"remove_run_directory\",\r\n path: runPath,\r\n bytes: null,\r\n harnessRoot: opts.harnessRoot,\r\n runId,\r\n ageMs: pathAgeMs(runPath, opts.now),\r\n });\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { listRunRecordsForHarnessRoot, runDirectoryAt } from \"./run-store.js\";\r\nimport { harnessRunsDir, harnessWorktreesDir } from \"./paths.js\";\r\nimport {\r\n collectFilesystemLiveRunKeys,\r\n RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n} from \"./run-metadata-retention.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\nimport { readJson, safeSlug, isPidAlive } from \"./util.js\";\r\n\r\nexport interface ActiveWorktreeGuardSnapshot {\r\n /** Resolved worktree paths that must keep dependency caches. */\r\n activeWorktreePaths: Set<string>;\r\n /** `${harnessRoot}\\0${runId}` keys for runs with at least one live worker. */\r\n liveRunKeys: Set<string>;\r\n}\r\n\r\nfunction workerHasRecentHarnessActivity(worker: HarnessWorkerRecord, now: number): boolean {\r\n const paths = [worker.heartbeatPath, worker.stdoutPath, worker.stderrPath];\r\n for (const target of paths) {\r\n if (!existsSync(target)) continue;\r\n try {\r\n const age = now - statSync(target).mtimeMs;\r\n if (Number.isFinite(age) && age >= 0 && age < RUN_METADATA_ACTIVE_SIGNAL_MS) return true;\r\n } catch {\r\n // ignore unreadable artifact\r\n }\r\n }\r\n return false;\r\n}\r\n\r\n/** Fast liveness probe \u2014 avoids full `computeWorkerStatus` during broad cleanup scans. */\r\nfunction isActiveHarnessWorker(worker: HarnessWorkerRecord, now: number): boolean {\r\n if (isPidAlive(worker.pid)) return true;\r\n if (worker.status === \"running\" && workerHasRecentHarnessActivity(worker, now)) return true;\r\n return false;\r\n}\r\n\r\n/** Collect worktrees/runs that still have live worker processes (current-run guard). */\r\nexport function collectActiveWorktreeGuards(\r\n harnessRoots: string[],\r\n now = Date.now(),\r\n): ActiveWorktreeGuardSnapshot {\r\n const activeWorktreePaths = new Set<string>();\r\n const liveRunKeys = new Set<string>();\r\n\r\n for (const harnessRoot of harnessRoots) {\r\n for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {\r\n let runHasLive = false;\r\n for (const name of Object.keys(run.workers || {})) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectoryAt(harnessRoot, run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker?.worktreePath) continue;\r\n const worktreePath = path.resolve(worker.worktreePath);\r\n if (!isActiveHarnessWorker(worker, now)) continue;\r\n runHasLive = true;\r\n activeWorktreePaths.add(worktreePath);\r\n }\r\n if (runHasLive) liveRunKeys.add(`${harnessRoot}\\0${run.id}`);\r\n }\r\n for (const key of collectFilesystemLiveRunKeys(harnessRoot)) {\r\n liveRunKeys.add(key);\r\n }\r\n }\r\n\r\n return { activeWorktreePaths, liveRunKeys };\r\n}\r\n\r\n/** True when a worktree path still exists under a live run (belt-and-suspenders). */\r\nexport function isWorktreeOnLiveRun(\r\n worktreePath: string,\r\n harnessRoot: string,\r\n runId: string | undefined,\r\n liveRunKeys: Set<string>,\r\n): boolean {\r\n if (!runId) return false;\r\n return liveRunKeys.has(`${harnessRoot}\\0${runId}`);\r\n}\r\n\r\nexport function worktreesDirForRoot(harnessRoot: string): string {\r\n return harnessWorktreesDir(harnessRoot);\r\n}\r\n\r\nexport function runsDirForRoot(harnessRoot: string): string {\r\n return harnessRunsDir(harnessRoot);\r\n}\r\n\r\nexport function harnessRootExists(harnessRoot: string): boolean {\r\n return existsSync(harnessRoot);\r\n}\r\n\r\nexport function listWorktreeRunIds(worktreesDir: string): string[] {\r\n if (!existsSync(worktreesDir)) return [];\r\n try {\r\n return readdirSync(worktreesDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { resolveDefaultRepo } from \"./default-repo.js\";\r\nimport { parseHeartbeat } from \"./heartbeat.js\";\r\nimport { harnessRunsDir, normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport { saveRun, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { canonicalWorkerDir, workerArtifactPaths } from \"./worker-metadata-paths.js\";\r\nimport { isPidAlive, readJson, safeSlug } from \"./util.js\";\r\n\r\n/** Recent heartbeat/stdout activity \u2014 treat run metadata as live. */\r\nexport const RUN_METADATA_ACTIVE_SIGNAL_MS = 15 * 60 * 1000;\r\n\r\nexport interface RunMetadataRetentionOutcome {\r\n runId: string;\r\n action: \"repaired_run_json\" | \"skipped\";\r\n reason: string;\r\n}\r\n\r\nexport interface RunMetadataRetentionResult {\r\n runs: RunMetadataRetentionOutcome[];\r\n}\r\n\r\n/** True when `targetPath` lives under `{harnessRoot}/runs/` (run + worker metadata). */\r\nexport function isHarnessRunMetadataPath(targetPath: string, harnessRoot: string): boolean {\r\n const resolved = path.resolve(targetPath);\r\n const runsDir = path.resolve(harnessRunsDir(harnessRoot));\r\n const rel = path.relative(runsDir, resolved);\r\n return rel !== \"..\" && !rel.startsWith(\"..\") && !path.isAbsolute(rel);\r\n}\r\n\r\nfunction listRunDirIds(runsDir: string): string[] {\r\n if (!existsSync(runsDir)) return [];\r\n try {\r\n return readdirSync(runsDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory() && entry.name !== \"runs\")\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction listWorkerNamesOnDisk(runDir: string): string[] {\r\n const workersDir = path.join(runDir, \"workers\");\r\n if (!existsSync(workersDir)) return [];\r\n try {\r\n return readdirSync(workersDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction pathRecentlyTouched(target: string, now: number, windowMs: number): boolean {\r\n if (!existsSync(target)) return false;\r\n try {\r\n const age = now - statSync(target).mtimeMs;\r\n return Number.isFinite(age) && age >= 0 && age < windowMs;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/** Worker dir still has live process or recent harness artifacts \u2014 retain metadata. */\r\nexport function workerDirHasActiveRetentionSignals(\r\n workerDir: string,\r\n now = Date.now(),\r\n windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n): boolean {\r\n if (!existsSync(workerDir)) return false;\r\n const artifacts = workerArtifactPaths(workerDir);\r\n const worker = readJson<{ status?: string; pid?: number } | undefined>(\r\n artifacts.workerJsonPath,\r\n undefined,\r\n );\r\n if (worker?.status === \"running\" && isPidAlive(worker.pid)) return true;\r\n const heartbeat = parseHeartbeat(artifacts.heartbeatPath);\r\n if (heartbeat.lastHeartbeatAt) {\r\n const age = now - Date.parse(heartbeat.lastHeartbeatAt);\r\n if (Number.isFinite(age) && age >= 0 && age < windowMs) return true;\r\n }\r\n if (pathRecentlyTouched(artifacts.stdoutPath, now, windowMs)) return true;\r\n if (pathRecentlyTouched(artifacts.heartbeatPath, now, windowMs)) return true;\r\n return false;\r\n}\r\n\r\n/** Any worker under a run dir still looks active \u2014 block metadata deletion/relocation. */\r\nexport function runDirHasActiveRetentionSignals(\r\n runDir: string,\r\n now = Date.now(),\r\n windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n): boolean {\r\n for (const name of listWorkerNamesOnDisk(runDir)) {\r\n if (workerDirHasActiveRetentionSignals(path.join(runDir, \"workers\", name), now, windowMs)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nfunction inferRepoFields(): Pick<HarnessRunRecord, \"repo\" | \"base\" | \"baseCommit\"> {\r\n const resolved = resolveDefaultRepo();\r\n return {\r\n repo: resolved?.repo ?? \"\",\r\n base: \"origin/main\",\r\n baseCommit: \"unknown\",\r\n };\r\n}\r\n\r\nfunction synthesizeRunFromDisk(harnessRoot: string, runId: string): HarnessRunRecord | null {\r\n const runDir = path.join(harnessRunsDir(harnessRoot), safeSlug(runId));\r\n if (!existsSync(runDir)) return null;\r\n const workerNames = listWorkerNamesOnDisk(runDir);\r\n if (workerNames.length === 0) return null;\r\n\r\n let createdAt: string;\r\n try {\r\n createdAt = statSync(runDir).birthtime.toISOString();\r\n } catch {\r\n createdAt = new Date().toISOString();\r\n }\r\n\r\n const workers: HarnessRunRecord[\"workers\"] = {};\r\n for (const name of workerNames) {\r\n const canonicalDir = canonicalWorkerDir(harnessRoot, runId, name);\r\n workers[name] = {\r\n workerDir: canonicalDir,\r\n statusPath: path.join(canonicalDir, \"worker.json\"),\r\n };\r\n }\r\n\r\n const hasActive = runDirHasActiveRetentionSignals(runDir);\r\n return {\r\n id: runId,\r\n name: runId,\r\n ...inferRepoFields(),\r\n status: hasActive ? \"running\" : \"needs_attention\",\r\n createdAt,\r\n workers,\r\n };\r\n}\r\n\r\n/**\r\n * Rebuild missing `run.json` files from on-disk worker dirs so reconcile/status\r\n * cannot go blind while worker processes or fresh artifacts remain.\r\n */\r\nexport function repairMissingRunMetadata(harnessRootInput?: string): RunMetadataRetentionResult {\r\n const harnessRoot = normalizeHarnessRoot(harnessRootInput ?? resolveHarnessRoot());\r\n const runsDir = harnessRunsDir(harnessRoot);\r\n const outcomes: RunMetadataRetentionOutcome[] = [];\r\n\r\n for (const runId of listRunDirIds(runsDir)) {\r\n const runJsonPath = path.join(runsDir, runId, \"run.json\");\r\n if (existsSync(runJsonPath)) {\r\n outcomes.push({\r\n runId,\r\n action: \"skipped\",\r\n reason: \"run.json present\",\r\n });\r\n continue;\r\n }\r\n\r\n const synthesized = synthesizeRunFromDisk(harnessRoot, runId);\r\n if (!synthesized) {\r\n outcomes.push({\r\n runId,\r\n action: \"skipped\",\r\n reason: \"no worker dirs on disk\",\r\n });\r\n continue;\r\n }\r\n\r\n saveRun(synthesized);\r\n outcomes.push({\r\n runId,\r\n action: \"repaired_run_json\",\r\n reason: runDirHasActiveRetentionSignals(path.join(runsDir, runId))\r\n ? \"synthesized run.json while worker artifacts still active\"\r\n : \"synthesized run.json from orphan worker metadata dirs\",\r\n });\r\n }\r\n\r\n return { runs: outcomes };\r\n}\r\n\r\n/** `${harnessRoot}\\0${runId}` keys for runs with filesystem active-retention signals. */\r\nexport function collectFilesystemLiveRunKeys(harnessRoot: string, now = Date.now()): Set<string> {\r\n const keys = new Set<string>();\r\n const runsDir = harnessRunsDir(harnessRoot);\r\n for (const runId of listRunDirIds(runsDir)) {\r\n const runDir = path.join(runsDir, runId);\r\n if (runDirHasActiveRetentionSignals(runDir, now)) {\r\n keys.add(`${harnessRoot}\\0${runId}`);\r\n }\r\n }\r\n return keys;\r\n}\r\n", "import path from \"node:path\";\r\nimport { loadUserConfig, saveUserConfig, type KynverUserConfig } from \"./config.js\";\r\nimport {\r\n discoverDefaultRepo,\r\n type DefaultRepoDiscoverySource,\r\n type DiscoveredDefaultRepo,\r\n} from \"./default-repo-discovery.js\";\r\nimport { displayUserPath, redactHomePath, resolveUserPath } from \"./path-values.js\";\r\n\r\nexport type DefaultRepoSource =\r\n | \"config\"\r\n | \"env_default_repo\"\r\n | \"env_harness_repo\"\r\n | DefaultRepoDiscoverySource;\r\n\r\nexport interface ResolvedDefaultRepo {\r\n repo: string;\r\n source: DefaultRepoSource;\r\n persistedInConfig: boolean;\r\n}\r\n\r\nexport interface ResolveDefaultRepoOptions {\r\n config?: KynverUserConfig;\r\n env?: NodeJS.ProcessEnv;\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}\r\n\r\nfunction expandConfiguredRepo(value: string): string {\r\n return path.resolve(resolveUserPath(value.trim()));\r\n}\r\n\r\nfunction fromConfigured(\r\n value: string | undefined,\r\n source: Extract<DefaultRepoSource, \"config\" | \"env_default_repo\" | \"env_harness_repo\">,\r\n persistedInConfig: boolean,\r\n): ResolvedDefaultRepo | null {\r\n const trimmed = value?.trim();\r\n if (!trimmed) return null;\r\n return {\r\n repo: expandConfiguredRepo(trimmed),\r\n source,\r\n persistedInConfig,\r\n };\r\n}\r\n\r\nexport function resolveDefaultRepo(opts: ResolveDefaultRepoOptions = {}): ResolvedDefaultRepo | null {\r\n const env = opts.env ?? process.env;\r\n const config = opts.config ?? loadUserConfig();\r\n\r\n const fromConfig = fromConfigured(config.defaultRepo, \"config\", true);\r\n if (fromConfig) return fromConfig;\r\n\r\n const fromDefaultEnv = fromConfigured(env.KYNVER_DEFAULT_REPO, \"env_default_repo\", false);\r\n if (fromDefaultEnv) return fromDefaultEnv;\r\n\r\n const fromHarnessEnv = fromConfigured(env.KYNVER_HARNESS_REPO, \"env_harness_repo\", false);\r\n if (fromHarnessEnv) return fromHarnessEnv;\r\n\r\n const discovered = discoverDefaultRepo({\r\n cwd: opts.cwd,\r\n runtimeModuleUrl: opts.runtimeModuleUrl,\r\n });\r\n if (!discovered) return null;\r\n\r\n return {\r\n repo: discovered.repo,\r\n source: discovered.source,\r\n persistedInConfig: false,\r\n };\r\n}\r\n\r\nexport function persistDefaultRepo(repo: string, existing?: KynverUserConfig): KynverUserConfig {\r\n const config: KynverUserConfig = {\r\n ...(existing ?? loadUserConfig()),\r\n defaultRepo: redactHomePath(path.resolve(repo)),\r\n };\r\n saveUserConfig(config);\r\n return config;\r\n}\r\n\r\nexport function remediateDefaultRepo(opts?: ResolveDefaultRepoOptions): {\r\n ok: true;\r\n resolved: ResolvedDefaultRepo;\r\n config: KynverUserConfig;\r\n} | {\r\n ok: false;\r\n reason: string;\r\n} {\r\n const existing = opts?.config ?? loadUserConfig();\r\n const resolved = resolveDefaultRepo({ ...opts, config: existing });\r\n if (!resolved) {\r\n return {\r\n ok: false,\r\n reason:\r\n \"No Kynver git checkout found. Clone the repo, cd into it, then run `kynver setup --repo /path/to/Kynver` (or export KYNVER_DEFAULT_REPO).\",\r\n };\r\n }\r\n\r\n if (resolved.persistedInConfig) {\r\n return { ok: true, resolved, config: existing };\r\n }\r\n\r\n const config = persistDefaultRepo(resolved.repo, existing);\r\n return {\r\n ok: true,\r\n resolved: { ...resolved, persistedInConfig: true, source: \"config\" },\r\n config,\r\n };\r\n}\r\n\r\nexport function formatResolvedDefaultRepo(resolved: ResolvedDefaultRepo): {\r\n defaultRepo: string;\r\n source: DefaultRepoSource;\r\n persistedInConfig: boolean;\r\n} {\r\n return {\r\n defaultRepo: displayUserPath(resolved.repo),\r\n source: resolved.source,\r\n persistedInConfig: resolved.persistedInConfig,\r\n };\r\n}\r\n\r\nexport type { DiscoveredDefaultRepo };\r\n", "import path from \"node:path\";\r\nimport { harnessRunsDir, normalizeHarnessRoot } from \"./paths.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\nconst NESTED_RUNS = `${path.sep}runs${path.sep}runs${path.sep}`;\r\n\r\n/** True when a persisted harness path contains the historical `runs/runs` segment. */\r\nexport function hasNestedRunsSegment(filePath: string): boolean {\r\n return filePath.includes(NESTED_RUNS);\r\n}\r\n\r\n/**\r\n * Rewrite a nested `.../runs/runs/<runId>/...` path to canonical `.../runs/<runId>/...`.\r\n * Returns the input unchanged when no nested segment is present.\r\n */\r\nexport function repairNestedRunsPath(filePath: string, harnessRoot: string): string {\r\n if (!hasNestedRunsSegment(filePath)) return filePath;\r\n const root = normalizeHarnessRoot(harnessRoot);\r\n const runsDir = harnessRunsDir(root);\r\n const marker = `${path.sep}runs${path.sep}runs${path.sep}`;\r\n const idx = filePath.indexOf(marker);\r\n if (idx < 0) return filePath;\r\n const tail = filePath.slice(idx + marker.length);\r\n return path.join(runsDir, tail);\r\n}\r\n\r\nexport function canonicalRunDir(harnessRoot: string, runId: string): string {\r\n return path.join(harnessRunsDir(normalizeHarnessRoot(harnessRoot)), safeSlug(runId));\r\n}\r\n\r\nexport function canonicalWorkerDir(harnessRoot: string, runId: string, workerName: string): string {\r\n return path.join(canonicalRunDir(harnessRoot, runId), \"workers\", safeSlug(workerName));\r\n}\r\n\r\n/** Historical mistaken layout when harness root ended in `/runs`. */\r\nexport function legacyNestedWorkerDir(harnessRoot: string, runId: string, workerName: string): string {\r\n const root = normalizeHarnessRoot(harnessRoot);\r\n return path.join(root, \"runs\", \"runs\", safeSlug(runId), \"workers\", safeSlug(workerName));\r\n}\r\n\r\nexport function workerArtifactFileNames(): readonly string[] {\r\n return [\r\n \"stdout.jsonl\",\r\n \"stderr.log\",\r\n \"heartbeat.jsonl\",\r\n \"last-status.json\",\r\n \"auto-complete.log\",\r\n \"worker.json\",\r\n ] as const;\r\n}\r\n\r\nexport function workerArtifactPaths(workerDir: string): {\r\n workerJsonPath: string;\r\n stdoutPath: string;\r\n stderrPath: string;\r\n heartbeatPath: string;\r\n lastStatusPath: string;\r\n} {\r\n return {\r\n workerJsonPath: path.join(workerDir, \"worker.json\"),\r\n stdoutPath: path.join(workerDir, \"stdout.jsonl\"),\r\n stderrPath: path.join(workerDir, \"stderr.log\"),\r\n heartbeatPath: path.join(workerDir, \"heartbeat.jsonl\"),\r\n lastStatusPath: path.join(workerDir, \"last-status.json\"),\r\n };\r\n}\r\n\r\n/** Resolve the best on-disk worker.json path for a run worker entry. */\r\nexport function resolveWorkerJsonPath(input: {\r\n harnessRoot: string;\r\n runId: string;\r\n workerName: string;\r\n statusPath?: string;\r\n}): string {\r\n const canonical = workerArtifactPaths(canonicalWorkerDir(input.harnessRoot, input.runId, input.workerName))\r\n .workerJsonPath;\r\n if (input.statusPath && !hasNestedRunsSegment(input.statusPath)) {\r\n return input.statusPath;\r\n }\r\n return canonical;\r\n}\r\n", "import { existsSync, rmSync } from \"node:fs\";\r\nimport { git } from \"./git.js\";\r\nimport type { CleanupAction, CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport {\r\n isHarnessBuildCachePath,\r\n isHarnessNextCachePath,\r\n isHarnessNodeModulesPath,\r\n} from \"./cleanup-harness-path-validate.js\";\r\nimport { removeHarnessGeneratedPath } from \"./cleanup-remove-path.js\";\r\nimport { isHarnessRunMetadataPath } from \"./run-metadata-retention.js\";\r\n\r\nexport { isHarnessBuildCachePath, isHarnessNextCachePath, isHarnessNodeModulesPath } from \"./cleanup-harness-path-validate.js\";\r\n\r\nfunction skipRunMetadataRemoval(candidate: CleanupCandidate): CleanupAction | null {\r\n const harnessRoot = candidate.harnessRoot;\r\n if (!harnessRoot || !isHarnessRunMetadataPath(candidate.path, harnessRoot)) return null;\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"run_metadata_protected\",\r\n };\r\n}\r\n\r\nfunction removeDependencyCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n const outcome = removeHarnessGeneratedPath(candidate, execute);\r\n return {\r\n ...candidate,\r\n bytes: outcome.bytes ?? candidate.bytes,\r\n executed: outcome.executed,\r\n skipped: outcome.skipped,\r\n skipReason: outcome.skipReason,\r\n error: outcome.error,\r\n };\r\n}\r\n\r\nexport function removeNodeModules(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeNextCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeBuildCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeRunDirectory(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n if (!existsSync(candidate.path)) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"missing_worktree\",\r\n };\r\n }\r\n if (!execute) {\r\n return { ...candidate, executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n try {\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n rmSync(candidate.path, { recursive: true, force: true });\r\n return {\r\n ...candidate,\r\n bytes: bytesBefore,\r\n executed: true,\r\n skipped: false,\r\n };\r\n } catch (error) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\nexport function removeWorktree(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n if (!existsSync(candidate.path)) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"missing_worktree\",\r\n };\r\n }\r\n if (!execute) {\r\n return { ...candidate, executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n const repo = candidate.repo;\r\n try {\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n if (repo) {\r\n git(repo, [\"worktree\", \"remove\", \"--force\", candidate.path], { allowFailure: true });\r\n }\r\n if (existsSync(candidate.path)) {\r\n rmSync(candidate.path, { recursive: true, force: true });\r\n }\r\n return {\r\n ...candidate,\r\n bytes: bytesBefore,\r\n executed: true,\r\n skipped: false,\r\n };\r\n } catch (error) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\n", "import { execFileSync } from \"node:child_process\";\r\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\n\r\nconst DEFAULT_DU_TIMEOUT_MS = 2_500;\r\n\r\nfunction directorySizeBytesDu(root: string, timeoutMs = DEFAULT_DU_TIMEOUT_MS): number | null {\r\n if (!existsSync(root)) return 0;\r\n try {\r\n const out = execFileSync(\"du\", [\"-sb\", root], {\r\n encoding: \"utf8\",\r\n timeout: timeoutMs,\r\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\r\n });\r\n const first = out.trim().split(/\\s+/)[0];\r\n const bytes = Number(first);\r\n return Number.isFinite(bytes) && bytes >= 0 ? bytes : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Best-effort directory size. Prefers `du -sb` (fast on large `node_modules`);\r\n * falls back to a capped walk. Returns null when entry cap is exceeded.\r\n */\r\nexport function directorySizeBytes(root: string, maxEntries = 50_000): number | null {\r\n if (!existsSync(root)) return 0;\r\n const duBytes = directorySizeBytesDu(root);\r\n if (duBytes !== null) return duBytes;\r\n let total = 0;\r\n let seen = 0;\r\n const stack: string[] = [root];\r\n while (stack.length > 0) {\r\n const current = stack.pop()!;\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(current);\r\n } catch {\r\n continue;\r\n }\r\n for (const name of entries) {\r\n if (seen++ > maxEntries) return null;\r\n const full = path.join(current, name);\r\n let st;\r\n try {\r\n st = statSync(full);\r\n } catch {\r\n continue;\r\n }\r\n if (st.isDirectory()) stack.push(full);\r\n else total += st.size;\r\n }\r\n }\r\n return total;\r\n}\r\n", "import { existsSync, rmSync } from \"node:fs\";\r\nimport type { CleanupCandidate, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport { harnessWorktreesDir } from \"./paths.js\";\r\nimport { pathHasForeignOwnedEntry } from \"./cleanup-path-ownership.js\";\r\nimport {\r\n HARNESS_ROOT_OWNED_CACHE_RUNBOOK,\r\n resolvePrivilegedCleanupMode,\r\n tryPrivilegedReclaimHarnessCache,\r\n} from \"./cleanup-privileged-remove.js\";\r\n\r\nexport interface RemoveHarnessPathOutcome {\r\n executed: boolean;\r\n skipped: boolean;\r\n skipReason?: CleanupSkipReason;\r\n error?: string;\r\n bytes?: number;\r\n privilegedReclaim?: boolean;\r\n}\r\n\r\ninterface RemoveHarnessGeneratedPathDeps {\r\n removePath?: typeof rmSync;\r\n hasForeignOwnedEntry?: typeof pathHasForeignOwnedEntry;\r\n}\r\n\r\nfunction permissionFailure(error: unknown): boolean {\r\n const code = (error as NodeJS.ErrnoException | undefined)?.code;\r\n return code === \"EACCES\" || code === \"EPERM\";\r\n}\r\n\r\nexport function removeHarnessGeneratedPath(\r\n candidate: CleanupCandidate,\r\n execute: boolean,\r\n deps: RemoveHarnessGeneratedPathDeps = {},\r\n): RemoveHarnessPathOutcome {\r\n if (!existsSync(candidate.path)) {\r\n return { executed: false, skipped: true, skipReason: \"missing_worktree\" };\r\n }\r\n if (!execute) {\r\n return { executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n\r\n const harnessRoot = candidate.harnessRoot;\r\n const worktreesDir = harnessRoot ? harnessWorktreesDir(harnessRoot) : null;\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n const bytesReported = bytesBefore ?? undefined;\r\n const removePath = deps.removePath ?? rmSync;\r\n const hasForeignOwnedEntry = deps.hasForeignOwnedEntry ?? pathHasForeignOwnedEntry;\r\n\r\n try {\r\n removePath(candidate.path, { recursive: true, force: true });\r\n return { executed: true, skipped: false, bytes: bytesReported };\r\n } catch (error) {\r\n if (!permissionFailure(error) || !harnessRoot || !worktreesDir) {\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n\r\n const foreign = hasForeignOwnedEntry(candidate.path);\r\n const mode = resolvePrivilegedCleanupMode();\r\n const shouldTryPrivileged = mode === \"force\" || (mode === \"auto\" && foreign);\r\n if (!shouldTryPrivileged) {\r\n return foreign\r\n ? {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(error as Error).message}; ${HARNESS_ROOT_OWNED_CACHE_RUNBOOK}`,\r\n }\r\n : {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n\r\n const reclaim = tryPrivilegedReclaimHarnessCache(candidate.path, harnessRoot, worktreesDir);\r\n if (reclaim.ok && reclaim.method === \"sudo_rm\") {\r\n return {\r\n executed: true,\r\n skipped: false,\r\n bytes: bytesReported,\r\n privilegedReclaim: true,\r\n };\r\n }\r\n\r\n if (reclaim.ok) {\r\n try {\r\n removePath(candidate.path, { recursive: true, force: true });\r\n return {\r\n executed: true,\r\n skipped: false,\r\n bytes: bytesReported,\r\n privilegedReclaim: true,\r\n };\r\n } catch (retryError) {\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(retryError as Error).message}; privileged chown succeeded but rm still failed`,\r\n };\r\n }\r\n }\r\n\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(error as Error).message}; privileged reclaim failed: ${reclaim.error}; ${HARNESS_ROOT_OWNED_CACHE_RUNBOOK}`,\r\n };\r\n }\r\n}\r\n", "import { lstatSync, readdirSync } from \"node:fs\";\r\n\r\nexport interface PathOwnershipInfo {\r\n uid: number;\r\n gid: number;\r\n /** True when the entry is not owned by the current process user/group. */\r\n foreign: boolean;\r\n}\r\n\r\nexport function readPathOwnership(targetPath: string): PathOwnershipInfo | null {\r\n try {\r\n const st = lstatSync(targetPath);\r\n const effectiveUid = typeof process.getuid === \"function\" ? process.getuid() : null;\r\n const effectiveGid = typeof process.getgid === \"function\" ? process.getgid() : null;\r\n const foreign =\r\n effectiveUid !== null &&\r\n (st.uid !== effectiveUid || (effectiveGid !== null && st.gid !== effectiveGid));\r\n return { uid: st.uid, gid: st.gid, foreign };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Shallow scan for foreign-owned entries (dependency caches are usually uniform). */\r\nexport function pathHasForeignOwnedEntry(targetPath: string, maxEntries = 32): boolean {\r\n const root = readPathOwnership(targetPath);\r\n if (!root) return false;\r\n if (root.foreign) return true;\r\n try {\r\n const names = readdirSync(targetPath);\r\n let checked = 0;\r\n for (const name of names) {\r\n if (checked >= maxEntries) break;\r\n const child = `${targetPath.replace(/\\/$/, \"\")}/${name}`;\r\n const info = readPathOwnership(child);\r\n checked += 1;\r\n if (info?.foreign) return true;\r\n }\r\n } catch {\r\n // unreadable \u2014 caller will hit EACCES on remove\r\n }\r\n return false;\r\n}\r\n", "import { spawnSync } from \"node:child_process\";\r\nimport path from \"node:path\";\r\nimport { isHarnessGeneratedCachePath } from \"./cleanup-harness-path-validate.js\";\r\n\r\nexport type PrivilegedCleanupMode = \"off\" | \"auto\" | \"force\";\r\n\r\nexport function resolvePrivilegedCleanupMode(): PrivilegedCleanupMode {\r\n const raw = (process.env.KYNVER_CLEANUP_PRIVILEGED ?? \"auto\").trim().toLowerCase();\r\n if (raw === \"0\" || raw === \"false\" || raw === \"off\" || raw === \"no\") return \"off\";\r\n if (raw === \"1\" || raw === \"true\" || raw === \"force\" || raw === \"yes\") return \"force\";\r\n return \"auto\";\r\n}\r\n\r\nfunction runSudoNonInteractive(argv: string[]): { ok: boolean; stderr: string } {\r\n const res = spawnSync(\"sudo\", [\"-n\", ...argv], {\r\n encoding: \"utf8\",\r\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\r\n });\r\n return {\r\n ok: res.status === 0,\r\n stderr: `${res.stderr ?? \"\"}${res.stdout ?? \"\"}`.trim(),\r\n };\r\n}\r\n\r\nexport interface PrivilegedReclaimResult {\r\n ok: boolean;\r\n method?: \"chown_then_rm\" | \"sudo_rm\";\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Reclaim a harness generated cache directory that is not owned by the daemon user.\r\n * Only operates on validated `worktrees/<run>/<worker>/{node_modules,.next,...}` paths.\r\n */\r\nexport function tryPrivilegedReclaimHarnessCache(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): PrivilegedReclaimResult {\r\n if (!isHarnessGeneratedCachePath(targetPath, harnessRoot, worktreesDir)) {\r\n return { ok: false, error: \"path is not an allowed harness generated cache\" };\r\n }\r\n const effectiveUid = typeof process.getuid === \"function\" ? process.getuid() : null;\r\n const effectiveGid = typeof process.getgid === \"function\" ? process.getgid() : null;\r\n if (effectiveUid === null || effectiveGid === null) {\r\n return { ok: false, error: \"privileged reclaim requires POSIX uid/gid\" };\r\n }\r\n\r\n const chown = runSudoNonInteractive([\r\n \"chown\",\r\n \"-R\",\r\n `${effectiveUid}:${effectiveGid}`,\r\n path.resolve(targetPath),\r\n ]);\r\n if (chown.ok) {\r\n return { ok: true, method: \"chown_then_rm\" };\r\n }\r\n\r\n const rm = runSudoNonInteractive([\"rm\", \"-rf\", path.resolve(targetPath)]);\r\n if (rm.ok) {\r\n return { ok: true, method: \"sudo_rm\" };\r\n }\r\n\r\n const detail = chown.stderr || rm.stderr || \"sudo -n failed (password required or not permitted)\";\r\n return {\r\n ok: false,\r\n error: detail,\r\n };\r\n}\r\n\r\nexport const HARNESS_ROOT_OWNED_CACHE_RUNBOOK =\r\n \"Root-owned harness caches require operator reclaim: configure passwordless sudo for chown/rm under ~/.kynver/harness/worktrees, or run `node scripts/reclaim-harness-root-owned-cache.mjs --execute` as the harness owner with sudo available. See docs/runbooks/harness-root-owned-cache-reclaim.md.\";\r\n", "import path from \"node:path\";\r\nimport type { CleanupSkipReason } from \"./cleanup-types.js\";\r\n\r\nfunction isHarnessDependencyCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n cacheDirName: \"node_modules\" | \".next\",\r\n): CleanupSkipReason | null {\r\n const resolved = path.resolve(targetPath);\r\n const suffix = `${path.sep}${cacheDirName}`;\r\n const cachePath = resolved.endsWith(suffix) ? resolved : null;\r\n if (!cachePath) return \"path_outside_harness\";\r\n const rel = path.relative(worktreesDir, cachePath);\r\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return \"path_outside_harness\";\r\n const parts = rel.split(path.sep);\r\n if (parts.length < 3 || parts[parts.length - 1] !== cacheDirName) return \"path_outside_harness\";\r\n if (!resolved.startsWith(path.resolve(harnessRoot))) return \"path_outside_harness\";\r\n return null;\r\n}\r\n\r\nexport function isHarnessNodeModulesPath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, \"node_modules\");\r\n}\r\n\r\nexport function isHarnessNextCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, \".next\");\r\n}\r\n\r\nexport function isHarnessBuildCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n const resolved = path.resolve(targetPath);\r\n const relToWt = path.relative(worktreesDir, resolved);\r\n if (relToWt.startsWith(\"..\") || path.isAbsolute(relToWt)) return \"path_outside_harness\";\r\n const parts = relToWt.split(path.sep);\r\n if (parts.length < 3) return \"path_outside_harness\";\r\n if (!resolved.startsWith(path.resolve(harnessRoot))) return \"path_outside_harness\";\r\n return null;\r\n}\r\n\r\nexport function isHarnessGeneratedCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): boolean {\r\n const resolved = path.resolve(targetPath);\r\n return (\r\n isHarnessNodeModulesPath(resolved, harnessRoot, worktreesDir) === null ||\r\n isHarnessNextCachePath(resolved, harnessRoot, worktreesDir) === null ||\r\n isHarnessBuildCachePath(resolved, harnessRoot, worktreesDir) === null\r\n );\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { HARNESS_BUILD_CACHE_RELATIVE_PATHS } from \"./cleanup-build-cache-paths.js\";\r\nimport { buildWorktreeIndex, type IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\n\r\nexport interface ScanHarnessOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n includeOrphans: boolean;\r\n runIdFilter?: string;\r\n index: Map<string, IndexedWorktree>;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction isPathInside(child: string, parent: string): boolean {\r\n const rel = path.relative(parent, child);\r\n return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\r\n}\r\n\r\nexport function scanNodeModulesCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n const nm = path.join(entry.worktreePath, \"node_modules\");\r\n if (!existsSync(nm)) continue;\r\n const resolved = path.resolve(nm);\r\n if (seen.has(resolved)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_node_modules\",\r\n path: resolved,\r\n bytes: null,\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n const nm = path.join(worktreePath, \"node_modules\");\r\n if (!existsSync(nm)) continue;\r\n const resolved = path.resolve(nm);\r\n if (seen.has(resolved)) continue;\r\n if (!isPathInside(resolved, opts.harnessRoot)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_node_modules\",\r\n path: resolved,\r\n bytes: null,\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nfunction collectBuildCacheForWorktree(\r\n worktreePath: string,\r\n opts: ScanHarnessOptions,\r\n seen: Set<string>,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): CleanupCandidate[] {\r\n const out: CleanupCandidate[] = [];\r\n for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {\r\n if (rel === \".next\") continue;\r\n const target = path.join(worktreePath, rel);\r\n if (!existsSync(target)) continue;\r\n const resolved = path.resolve(target);\r\n if (seen.has(resolved)) continue;\r\n if (!isPathInside(resolved, opts.harnessRoot)) continue;\r\n seen.add(resolved);\r\n out.push({\r\n kind: \"remove_build_cache\",\r\n path: resolved,\r\n bytes: null,\r\n runId: meta.runId,\r\n worker: meta.worker,\r\n repo: meta.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n return out;\r\n}\r\n\r\nexport function scanBuildCacheCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n candidates.push(\r\n ...collectBuildCacheForWorktree(entry.worktreePath, opts, seen, {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n }),\r\n );\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n candidates.push(\r\n ...collectBuildCacheForWorktree(worktreePath, opts, seen, {\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n }),\r\n );\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nexport function scanWorktreeCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n // Indexed worktrees scan when either an explicit age threshold is set OR the\r\n // operator opted in via `--include-orphans` (the salvage gates in\r\n // `skipWorktreeRemoval` are the primary protection at age 0). Orphan scan\r\n // additionally requires `--include-orphans` and applies the orphan-safety\r\n // check via `assessOrphanWorktreeSafety`.\r\n const indexedEnabled = opts.worktreesAgeMs > 0 || opts.includeOrphans;\r\n const orphanEnabled = opts.includeOrphans;\r\n if (!indexedEnabled && !orphanEnabled) return [];\r\n\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n if (indexedEnabled) {\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n const resolved = entry.worktreePath;\r\n if (!existsSync(resolved)) continue;\r\n if (seen.has(resolved)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: resolved,\r\n bytes: null,\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n if (!orphanEnabled || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n // Track index entries so we can identify true orphans on disk.\r\n const indexedPaths = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n indexedPaths.add(path.resolve(entry.worktreePath));\r\n }\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n let workerEntries;\r\n try {\r\n workerEntries = readdirSync(runPath, { withFileTypes: true });\r\n } catch {\r\n continue;\r\n }\r\n for (const workerEntry of workerEntries) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.resolve(path.join(runPath, workerEntry.name));\r\n if (seen.has(worktreePath)) continue;\r\n if (indexedPaths.has(worktreePath)) continue;\r\n if (!isPathInside(worktreePath, opts.harnessRoot)) continue;\r\n seen.add(worktreePath);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: worktreePath,\r\n bytes: null,\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n ageMs: pathAgeMs(worktreePath, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupActionKind, CleanupCandidate } from \"./cleanup-types.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\n\r\nconst DEPENDENCY_CACHE_DIRS: Array<{ dirName: string; kind: CleanupActionKind }> = [\r\n { dirName: \"node_modules\", kind: \"remove_node_modules\" },\r\n { dirName: \".next\", kind: \"remove_next_cache\" },\r\n];\r\n\r\nexport interface ScanDependencyCacheOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n nodeModulesAgeMs: number;\r\n includeOrphans?: boolean;\r\n runIdFilter?: string;\r\n index: Map<string, IndexedWorktree>;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction isPathInside(child: string, parent: string): boolean {\r\n const rel = path.relative(parent, child);\r\n return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\r\n}\r\n\r\nfunction pushCandidate(\r\n candidates: CleanupCandidate[],\r\n seen: Set<string>,\r\n opts: ScanDependencyCacheOptions,\r\n targetPath: string,\r\n kind: CleanupActionKind,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): void {\r\n if (!existsSync(targetPath)) return;\r\n const resolved = path.resolve(targetPath);\r\n if (seen.has(resolved)) return;\r\n if (!isPathInside(resolved, opts.harnessRoot)) return;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind,\r\n path: resolved,\r\n bytes: null,\r\n harnessRoot: opts.harnessRoot,\r\n runId: meta.runId,\r\n worker: meta.worker,\r\n repo: meta.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n}\r\n\r\nfunction scanWorktreeDependencyCaches(\r\n candidates: CleanupCandidate[],\r\n seen: Set<string>,\r\n opts: ScanDependencyCacheOptions,\r\n worktreePath: string,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): void {\r\n for (const entry of DEPENDENCY_CACHE_DIRS) {\r\n pushCandidate(candidates, seen, opts, path.join(worktreePath, entry.dirName), entry.kind, meta);\r\n }\r\n}\r\n\r\n/** Scan indexed + on-disk worktrees for generated dependency caches. */\r\nexport function scanDependencyCacheCandidates(opts: ScanDependencyCacheOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n scanWorktreeDependencyCaches(candidates, seen, opts, entry.worktreePath, {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n });\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n let workerEntries;\r\n try {\r\n workerEntries = readdirSync(runPath, { withFileTypes: true });\r\n } catch {\r\n continue;\r\n }\r\n for (const workerEntry of workerEntries) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, {\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { git } from \"./git.js\";\r\nimport type { ScanHarnessOptions } from \"./cleanup-scan.js\";\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\ninterface PorcelainWorktree {\r\n path: string;\r\n branch?: string;\r\n head?: string;\r\n bare?: boolean;\r\n}\r\n\r\nfunction parseWorktreePorcelain(output: string): PorcelainWorktree[] {\r\n const records: PorcelainWorktree[] = [];\r\n let current: PorcelainWorktree | null = null;\r\n for (const line of output.split(\"\\n\")) {\r\n if (!line.trim()) continue;\r\n const [key, ...rest] = line.split(\" \");\r\n const value = rest.join(\" \");\r\n if (key === \"worktree\") {\r\n if (current) records.push(current);\r\n current = { path: value };\r\n continue;\r\n }\r\n if (!current) continue;\r\n if (key === \"branch\") current.branch = value;\r\n if (key === \"HEAD\") current.head = value;\r\n if (key === \"bare\") current.bare = true;\r\n }\r\n if (current) records.push(current);\r\n return records;\r\n}\r\n\r\nfunction isUnderWorktreesDir(worktreePath: string, worktreesDir: string): boolean {\r\n const rel = path.relative(path.resolve(worktreesDir), path.resolve(worktreePath));\r\n return rel !== \"\" && !rel.startsWith(\"..\") && !path.isAbsolute(rel);\r\n}\r\n\r\nfunction isCleanWorktree(worktreePath: string, repoRoot: string): boolean {\r\n try {\r\n const porcelain = git(repoRoot, [\"-C\", worktreePath, \"status\", \"--porcelain\"], {\r\n allowFailure: true,\r\n });\r\n return !String(porcelain || \"\").trim();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Secondary git worktrees under the harness layout that are clean but not indexed\r\n * (aborted duplicate attempts). Uses `git worktree remove` during execute.\r\n */\r\nexport function scanDuplicateWorktreeCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return [];\r\n\r\n const repos = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n if (entry.run.repo) repos.add(path.resolve(entry.run.repo));\r\n }\r\n\r\n const indexedPaths = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n indexedPaths.add(path.resolve(entry.worktreePath));\r\n }\r\n\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const repoRoot of repos) {\r\n let porcelain: string;\r\n try {\r\n porcelain = git(repoRoot, [\"worktree\", \"list\", \"--porcelain\"], { allowFailure: true });\r\n } catch {\r\n continue;\r\n }\r\n const worktrees = parseWorktreePorcelain(porcelain);\r\n for (const wt of worktrees) {\r\n const resolved = path.resolve(wt.path);\r\n if (resolved === path.resolve(repoRoot)) continue;\r\n if (!isUnderWorktreesDir(resolved, opts.worktreesDir)) continue;\r\n if (indexedPaths.has(resolved)) continue;\r\n if (seen.has(resolved)) continue;\r\n if (!existsSync(resolved)) continue;\r\n if (!isCleanWorktree(resolved, repoRoot)) continue;\r\n\r\n const rel = path.relative(opts.worktreesDir, resolved);\r\n const parts = rel.split(path.sep);\r\n const runId = parts[0];\r\n const worker = parts[1] ?? \"unknown\";\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: resolved,\r\n bytes: null,\r\n runId,\r\n worker,\r\n repo: repoRoot,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import path from \"node:path\";\r\nimport {\r\n getPaths,\r\n listRunRecordsForHarnessRoot,\r\n loadWorker,\r\n runDirectoryAt,\r\n type HarnessRunRecord,\r\n} from \"./run-store.js\";\r\nimport type { HarnessWorkerRecord, RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\n\r\nexport interface IndexedWorktree {\r\n harnessRoot?: string;\r\n worktreePath: string;\r\n runId: string;\r\n workerName: string;\r\n run: HarnessRunRecord;\r\n worker: HarnessWorkerRecord;\r\n /** Populated lazily via `indexedWorktreeStatus()` during guard evaluation. */\r\n status?: RawHarnessWorkerStatus;\r\n}\r\n\r\nexport function buildWorktreeIndex(): Map<string, IndexedWorktree> {\r\n const { harnessRoot } = getPaths();\r\n return buildWorktreeIndexAt(harnessRoot);\r\n}\r\n\r\nexport function buildWorktreeIndexAt(harnessRoot: string): Map<string, IndexedWorktree> {\r\n const index = new Map<string, IndexedWorktree>();\r\n for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {\r\n for (const name of Object.keys(run.workers || {})) {\r\n const workerPath = path.join(\r\n runDirectoryAt(harnessRoot, run.id),\r\n \"workers\",\r\n safeSlug(name),\r\n \"worker.json\",\r\n );\r\n const worker = readJson<HarnessWorkerRecord | undefined>(workerPath, undefined);\r\n if (!worker?.worktreePath) continue;\r\n index.set(path.resolve(worker.worktreePath), {\r\n harnessRoot,\r\n worktreePath: path.resolve(worker.worktreePath),\r\n runId: run.id,\r\n workerName: name,\r\n run,\r\n worker,\r\n });\r\n }\r\n }\r\n return index;\r\n}\r\n\r\n/** Load worker when index miss but path is known from disk layout. */\r\nexport function loadIndexedWorker(runId: string, workerName: string): HarnessWorkerRecord | null {\r\n try {\r\n return loadWorker(runId, workerName);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n", "import type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport {\r\n DEFAULT_MAX_ACTIONS_PER_SWEEP,\r\n DEFAULT_NODE_MODULES_AGE_MS,\r\n DEFAULT_RUN_DIRECTORIES_AGE_MS,\r\n DEFAULT_TERMINAL_WORKTREES_AGE_MS,\r\n DEFAULT_WORKTREES_AGE_MS,\r\n type HarnessCleanupOptions,\r\n} from \"./cleanup-types.js\";\r\n\r\nfunction envFlag(name: string): boolean {\r\n const v = process.env[name];\r\n return v === \"1\" || v === \"true\" || v === \"yes\";\r\n}\r\n\r\nfunction envMs(name: string, fallback: number): number {\r\n const raw = process.env[name];\r\n if (!raw) return fallback;\r\n const n = Number(raw);\r\n return Number.isFinite(n) && n >= 0 ? n : fallback;\r\n}\r\n\r\nexport interface ResolvedHarnessRetention {\r\n execute: boolean;\r\n finalizeStaleRuns: boolean;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n terminalWorktreesAgeMs: number;\r\n runDirectoriesAgeMs: number;\r\n maxActionsPerSweep: number;\r\n includeOrphans: boolean;\r\n runIdFilter?: string;\r\n accountBytes: boolean;\r\n /** Cap filesystem walk depth per run dir in `harnessStorageSnapshot` (0 = counts only). */\r\n storagePerRunEntryCap: number | null;\r\n /** Per-candidate walk cap when `du` is unavailable (default 2k). */\r\n byteAccountingEntryCap: number;\r\n diskPressure?: boolean;\r\n diskGate?: DispatchNextDiskGateShape;\r\n}\r\n\r\n/** Merge CLI options with operator env defaults (pipeline + `kynver cleanup`). */\r\nexport function resolveHarnessRetention(\r\n options: HarnessCleanupOptions = {},\r\n): ResolvedHarnessRetention {\r\n const execute =\r\n options.execute === true ||\r\n (options.execute !== false && envFlag(\"KYNVER_CLEANUP_EXECUTE\"));\r\n const finalizeStaleRuns =\r\n options.finalizeStaleRuns !== false && !envFlag(\"KYNVER_CLEANUP_SKIP_FINALIZE\");\r\n const nodeModulesAgeMs =\r\n options.nodeModulesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_NODE_MODULES_AGE_MS\", DEFAULT_NODE_MODULES_AGE_MS);\r\n const worktreesAgeMs =\r\n options.worktreesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_WORKTREES_AGE_MS\", 0);\r\n const terminalWorktreesAgeMs =\r\n options.terminalWorktreesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_TERMINAL_WORKTREES_AGE_MS\", DEFAULT_TERMINAL_WORKTREES_AGE_MS);\r\n const runDirectoriesAgeMs =\r\n options.runDirectoriesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_RUN_DIRECTORIES_AGE_MS\", DEFAULT_RUN_DIRECTORIES_AGE_MS);\r\n const maxActionsPerSweep =\r\n options.maxActionsPerSweep ??\r\n envMs(\"KYNVER_CLEANUP_MAX_ACTIONS_PER_SWEEP\", DEFAULT_MAX_ACTIONS_PER_SWEEP);\r\n const includeOrphans =\r\n options.includeOrphans === true || envFlag(\"KYNVER_CLEANUP_INCLUDE_ORPHANS\");\r\n const scopeAll = envFlag(\"KYNVER_CLEANUP_SCOPE_ALL\") || process.env.KYNVER_CLEANUP_SCOPE === \"all\";\r\n const runIdFilter = scopeAll\r\n ? options.runIdFilter\r\n : options.runIdFilter ?? (process.env.KYNVER_CLEANUP_RUN_ID || undefined);\r\n const accountBytes = options.accountBytes !== false && !envFlag(\"KYNVER_CLEANUP_SKIP_BYTE_ACCOUNTING\");\r\n const storageCapEnv = envMs(\"KYNVER_CLEANUP_STORAGE_ENTRY_CAP\", 2_000);\r\n const storagePerRunEntryCap =\r\n options.storagePerRunEntryCap !== undefined\r\n ? options.storagePerRunEntryCap\r\n : accountBytes\r\n ? storageCapEnv > 0\r\n ? storageCapEnv\r\n : null\r\n : null;\r\n const byteCapEnv = envMs(\"KYNVER_CLEANUP_BYTE_ENTRY_CAP\", 2_000);\r\n const byteAccountingEntryCap =\r\n options.byteAccountingEntryCap ??\r\n (Number.isFinite(byteCapEnv) && byteCapEnv > 0 ? Math.floor(byteCapEnv) : 2_000);\r\n\r\n return {\r\n execute,\r\n finalizeStaleRuns,\r\n nodeModulesAgeMs,\r\n worktreesAgeMs: worktreesAgeMs > 0 ? worktreesAgeMs : 0,\r\n terminalWorktreesAgeMs: terminalWorktreesAgeMs >= 0 ? terminalWorktreesAgeMs : 0,\r\n runDirectoriesAgeMs: runDirectoriesAgeMs >= 0 ? runDirectoriesAgeMs : 0,\r\n maxActionsPerSweep:\r\n Number.isFinite(maxActionsPerSweep) && maxActionsPerSweep > 0\r\n ? Math.floor(maxActionsPerSweep)\r\n : DEFAULT_MAX_ACTIONS_PER_SWEEP,\r\n includeOrphans,\r\n runIdFilter: runIdFilter ? String(runIdFilter) : undefined,\r\n accountBytes,\r\n storagePerRunEntryCap,\r\n byteAccountingEntryCap,\r\n };\r\n}\r\n\r\n/** Pipeline tick: dry-run by default; global scope when `KYNVER_CLEANUP_SCOPE=all`. */\r\nexport function resolvePipelineHarnessRetention(runId?: string): ResolvedHarnessRetention {\r\n const scopeAll = process.env.KYNVER_CLEANUP_SCOPE === \"all\";\r\n const envWorktrees = Number(process.env.KYNVER_CLEANUP_WORKTREES_AGE_MS);\r\n const worktreesAgeMs = scopeAll\r\n ? Number.isFinite(envWorktrees) && envWorktrees > 0\r\n ? envWorktrees\r\n : DEFAULT_WORKTREES_AGE_MS\r\n : Number.isFinite(envWorktrees) && envWorktrees > 0\r\n ? envWorktrees\r\n : 0;\r\n return resolveHarnessRetention({\r\n runIdFilter: scopeAll ? undefined : runId,\r\n worktreesAgeMs,\r\n terminalWorktreesAgeMs: scopeAll ? DEFAULT_TERMINAL_WORKTREES_AGE_MS : undefined,\r\n runDirectoriesAgeMs: scopeAll ? DEFAULT_RUN_DIRECTORIES_AGE_MS : undefined,\r\n includeOrphans: scopeAll ? true : undefined,\r\n finalizeStaleRuns: true,\r\n accountBytes: true,\r\n });\r\n}\r\n", "import { existsSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { gitCapture } from \"./git.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport type { CleanupSkipReason } from \"./cleanup-types.js\";\r\n\r\nconst DEFAULT_HEARTBEAT_FRESH_MS = 30 * 60 * 1000;\r\n\r\nexport interface OrphanSafetyInput {\r\n worktreePath: string;\r\n harnessRoot: string;\r\n runId?: string;\r\n workerName?: string;\r\n heartbeatFreshMs?: number;\r\n now?: number;\r\n}\r\n\r\n/**\r\n * Inspect filesystem signals for an orphan worktree (no run/worker.json index entry).\r\n *\r\n * Returns a `CleanupSkipReason` when removal is unsafe, or `null` when the orphan\r\n * appears safe to delete. Conservative on errors \u2014 any unreadable git state or\r\n * unexpected layout returns `pr_or_unmerged_commits` so genuine work is preserved.\r\n */\r\nexport function assessOrphanWorktreeSafety(\r\n input: OrphanSafetyInput,\r\n): CleanupSkipReason | null {\r\n const now = input.now ?? Date.now();\r\n const heartbeatFreshMs = input.heartbeatFreshMs ?? DEFAULT_HEARTBEAT_FRESH_MS;\r\n\r\n if (!existsSync(input.worktreePath)) return null;\r\n\r\n if (input.runId && input.workerName) {\r\n const heartbeatPath = path.join(\r\n input.harnessRoot,\r\n \"runs\",\r\n input.runId,\r\n \"workers\",\r\n input.workerName,\r\n \"heartbeat.jsonl\",\r\n );\r\n try {\r\n const mtime = statSync(heartbeatPath).mtimeMs;\r\n if (now - mtime < heartbeatFreshMs) return \"active_worker\";\r\n } catch {\r\n // No heartbeat \u2014 fine, orphan is fully detached.\r\n }\r\n }\r\n\r\n const gitDir = path.join(input.worktreePath, \".git\");\r\n if (!existsSync(gitDir)) return null;\r\n\r\n const porcelain = gitCapture(input.worktreePath, [\"status\", \"--porcelain\"]);\r\n if (porcelain.status !== 0) return \"pr_or_unmerged_commits\";\r\n const dirtyLines = porcelain.stdout\r\n .split(\"\\n\")\r\n .map((line) => line.trim())\r\n .filter((line) => line.length > 0);\r\n if (materialWorktreeChanges(dirtyLines).length > 0) return \"dirty_worktree\";\r\n\r\n const upstreamAhead = gitCapture(input.worktreePath, [\r\n \"rev-list\",\r\n \"--count\",\r\n \"@{u}..HEAD\",\r\n ]);\r\n if (upstreamAhead.status === 0) {\r\n const count = Number(upstreamAhead.stdout.trim());\r\n if (Number.isFinite(count) && count > 0) return \"pr_or_unmerged_commits\";\r\n }\r\n\r\n const mainAhead = gitCapture(input.worktreePath, [\r\n \"rev-list\",\r\n \"--count\",\r\n \"origin/main..HEAD\",\r\n ]);\r\n if (mainAhead.status !== 0) {\r\n // Upstream may be gone after PR merge; when origin/main is also unreachable, preserve work.\r\n if (upstreamAhead.status !== 0) return \"pr_or_unmerged_commits\";\r\n return null;\r\n }\r\n const mainCount = Number(mainAhead.stdout.trim());\r\n if (Number.isFinite(mainCount) && mainCount > 0) return \"pr_or_unmerged_commits\";\r\n\r\n return null;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { harnessWorktreesDir, normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\n\r\nexport interface HarnessStorageSnapshot {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n /** Sum of per-run directory sizes. `null` when scan exceeded entry cap. */\r\n worktreesBytes: number | null;\r\n /** Top-level run directory count under `worktreesDir`. */\r\n runCount: number;\r\n /** Total worktree (worker) directories across all runs. */\r\n workerCount: number;\r\n /** Earliest run-directory mtime, ISO string. `null` when no runs present. */\r\n oldestRunAt: string | null;\r\n scannedAt: string;\r\n}\r\n\r\ninterface ScanOptions {\r\n harnessRoot?: string;\r\n /** Cap per directorySizeBytes call. Default 50k entries \u2014 keeps the snapshot fast for monitor ticks. Set null/0 to return bytes=null without scanning. */\r\n perRunEntryCap?: number | null;\r\n now?: number;\r\n}\r\n\r\n/**\r\n * Read-only summary of harness worktree storage usage. Surfaced in cleanup\r\n * summaries and consumable by monitor/Command Center to flag disk pressure\r\n * before WSL runs out of space again.\r\n */\r\nexport function harnessStorageSnapshot(opts: ScanOptions = {}): HarnessStorageSnapshot {\r\n const harnessRoot = normalizeHarnessRoot(opts.harnessRoot ?? resolveHarnessRoot());\r\n const worktreesDir = harnessWorktreesDir(harnessRoot);\r\n const now = opts.now ?? Date.now();\r\n const scannedAt = new Date(now).toISOString();\r\n\r\n if (!existsSync(worktreesDir)) {\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: 0,\r\n runCount: 0,\r\n workerCount: 0,\r\n oldestRunAt: null,\r\n scannedAt,\r\n };\r\n }\r\n\r\n let totalBytes: number | null = 0;\r\n let runCount = 0;\r\n let workerCount = 0;\r\n let oldestMs: number | null = null;\r\n\r\n let entries;\r\n try {\r\n entries = readdirSync(worktreesDir, { withFileTypes: true });\r\n } catch {\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: null,\r\n runCount: 0,\r\n workerCount: 0,\r\n oldestRunAt: null,\r\n scannedAt,\r\n };\r\n }\r\n\r\n for (const runEntry of entries) {\r\n if (!runEntry.isDirectory()) continue;\r\n runCount += 1;\r\n const runPath = path.join(worktreesDir, runEntry.name);\r\n try {\r\n const st = statSync(runPath);\r\n oldestMs = oldestMs === null ? st.mtimeMs : Math.min(oldestMs, st.mtimeMs);\r\n } catch {\r\n // ignore unreadable run dir\r\n }\r\n try {\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (workerEntry.isDirectory()) workerCount += 1;\r\n }\r\n } catch {\r\n // ignore unreadable run dir\r\n }\r\n if (totalBytes !== null && opts.perRunEntryCap !== null) {\r\n const cap = opts.perRunEntryCap ?? 50_000;\r\n if (cap <= 0) {\r\n totalBytes = null;\r\n } else {\r\n const runBytes = directorySizeBytes(runPath, cap);\r\n if (runBytes === null) totalBytes = null;\r\n else totalBytes += runBytes;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: totalBytes,\r\n runCount,\r\n workerCount,\r\n oldestRunAt: oldestMs === null ? null : new Date(oldestMs).toISOString(),\r\n scannedAt,\r\n };\r\n}\r\n", "import { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\n\r\n/** Operator-known harness trees that accumulate stale dependency caches. */\r\nexport const WELL_KNOWN_HARNESS_SCAN_ROOTS = [\r\n \"/var/tmp/kynver-harness\",\r\n path.join(homedir(), \".openclaw\", \"harness\"),\r\n] as const;\r\n\r\nfunction addRoot(seen: Set<string>, roots: string[], candidate: string | undefined): void {\r\n if (!candidate?.trim()) return;\r\n const resolved = normalizeHarnessRoot(candidate.trim());\r\n if (seen.has(resolved)) return;\r\n seen.add(resolved);\r\n roots.push(resolved);\r\n}\r\n\r\n/**\r\n * Deduped harness roots to scan for dependency-cache GC. Includes the active\r\n * configured root plus well-known legacy/tmp trees when they exist on disk.\r\n */\r\nfunction shouldScanWellKnownRoots(options: { scanWellKnown?: boolean }): boolean {\r\n if (options.scanWellKnown != null) return options.scanWellKnown;\r\n if (process.env.VITEST === \"true\") return false;\r\n return (\r\n process.env.KYNVER_CLEANUP_SCAN_WELL_KNOWN !== \"0\" &&\r\n ![\"0\", \"false\", \"no\"].includes((process.env.KYNVER_CLEANUP_SCAN_WELL_KNOWN ?? \"\").toLowerCase())\r\n );\r\n}\r\n\r\nexport function resolveHarnessScanRoots(\r\n options: { harnessRoot?: string; scanWellKnown?: boolean } = {},\r\n): string[] {\r\n const seen = new Set<string>();\r\n const roots: string[] = [];\r\n\r\n addRoot(seen, roots, options.harnessRoot ?? resolveHarnessRoot());\r\n\r\n const extra = process.env.KYNVER_CLEANUP_EXTRA_ROOTS?.split(\",\")\r\n .map((part) => part.trim())\r\n .filter(Boolean);\r\n for (const candidate of extra ?? []) addRoot(seen, roots, candidate);\r\n\r\n if (shouldScanWellKnownRoots(options)) {\r\n for (const candidate of WELL_KNOWN_HARNESS_SCAN_ROOTS) {\r\n const resolved = path.resolve(candidate);\r\n if (!seen.has(resolved) && existsSync(resolved)) addRoot(seen, roots, resolved);\r\n }\r\n }\r\n\r\n return roots;\r\n}\r\n", "import type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport { observeRunnerDiskGate, type ObserveDiskGateInput } from \"./disk-gate.js\";\r\nimport type { ResolvedHarnessRetention } from \"./cleanup-retention-config.js\";\r\nimport { DEFAULT_WORKTREES_AGE_MS } from \"./cleanup-types.js\";\r\n\r\nfunction envFlag(name: string): boolean {\r\n const v = process.env[name];\r\n return v === \"1\" || v === \"true\" || v === \"yes\";\r\n}\r\n\r\nfunction envNumber(name: string, fallback: number): number {\r\n const raw = process.env[name];\r\n if (!raw) return fallback;\r\n const n = Number(raw);\r\n return Number.isFinite(n) ? n : fallback;\r\n}\r\n\r\nexport interface CleanupDiskPressureShape {\r\n diskGate: DispatchNextDiskGateShape;\r\n /** Root filesystem (or override) is at/above the guard threshold. */\r\n pressured: boolean;\r\n maxUsedPercent: number;\r\n}\r\n\r\nexport function observeCleanupDiskPressure(input: ObserveDiskGateInput = {}): CleanupDiskPressureShape {\r\n const diskPath = input.diskPath?.trim() || process.env.KYNVER_DISK_GUARD_PATH?.trim() || \"/\";\r\n const maxUsedPercent = envNumber(\"KYNVER_DISK_GUARD_MAX_USED_PERCENT\", 75);\r\n const diskGate = observeRunnerDiskGate({\r\n ...input,\r\n diskPath,\r\n diskMaxUsedPercent: input.diskMaxUsedPercent ?? maxUsedPercent,\r\n });\r\n let pressured = !diskGate.ok || diskGate.usedPercent >= maxUsedPercent;\r\n\r\n // KYNVER_CLEANUP_DISK_PRESSURE_FORCE=none|pressured overrides the statfs\r\n // verdict. Quota-overlay hosts (managed sandboxes, container quotas) report\r\n // a huge filesystem with little \"available\" space, so the computed\r\n // used-percent reads as critically full even when the workload has plenty\r\n // of headroom \u2014 silently escalating every cleanup into an execute-mode,\r\n // include-orphans sweep. `none` pins pressure off for such hosts (and for\r\n // hermetic tests); `pressured` forces escalation for drills.\r\n const force = process.env.KYNVER_CLEANUP_DISK_PRESSURE_FORCE?.trim().toLowerCase();\r\n if (force === \"none\" || force === \"off\" || force === \"0\") pressured = false;\r\n else if (force === \"pressured\" || force === \"on\" || force === \"1\") pressured = true;\r\n\r\n return { diskGate, pressured, maxUsedPercent };\r\n}\r\n\r\n/**\r\n * Under disk pressure, reclaim generated dependency caches aggressively while\r\n * keeping source worktrees and stricter worktree deletion rules unchanged.\r\n */\r\nexport function applyDiskPressureToRetention(\r\n retention: ResolvedHarnessRetention,\r\n pressure: CleanupDiskPressureShape,\r\n): ResolvedHarnessRetention {\r\n if (!pressure.pressured) return retention;\r\n const executeOnPressure =\r\n retention.execute || !envFlag(\"KYNVER_CLEANUP_DRY_RUN_ON_PRESSURE\");\r\n return {\r\n ...retention,\r\n execute: executeOnPressure,\r\n nodeModulesAgeMs: 0,\r\n // Disk pressure means the current-run-only cleanup scope has already fallen\r\n // behind. Expand the sweep to every known harness root/run, but keep the\r\n // worktree salvage/PR/dirty/live-worker guards in the cleanup pipeline.\r\n runIdFilter: undefined,\r\n includeOrphans: true,\r\n terminalWorktreesAgeMs: 0,\r\n runDirectoriesAgeMs: 0,\r\n worktreesAgeMs: retention.worktreesAgeMs > 0 ? retention.worktreesAgeMs : DEFAULT_WORKTREES_AGE_MS,\r\n diskPressure: true,\r\n diskGate: pressure.diskGate,\r\n };\r\n}\r\n", "/** stderr progress lines so broad cleanup scans do not appear hung before JSON output. */\r\nexport function emitCleanupProgress(phase: string, detail?: string): void {\r\n if (process.env.KYNVER_CLEANUP_QUIET === \"1\") return;\r\n const suffix = detail ? `: ${detail}` : \"\";\r\n console.error(`[kynver cleanup] ${phase}${suffix}`);\r\n}\r\n", "import { gitCapture } from \"./git.js\";\r\n\r\n/** Per-sweep memo for cheap ahead-of-main probes during worktree guard passes. */\r\nexport class CleanupGitRevCache {\r\n private readonly aheadOfMain = new Map<string, number | null>();\r\n\r\n countAheadOfMain(worktreePath: string, base = \"origin/main\"): number | null {\r\n const key = `${worktreePath}\\0${base}`;\r\n if (this.aheadOfMain.has(key)) return this.aheadOfMain.get(key) ?? null;\r\n const result = gitCapture(worktreePath, [\"rev-list\", \"--count\", `${base}..HEAD`]);\r\n if (result.status !== 0) {\r\n this.aheadOfMain.set(key, null);\r\n return null;\r\n }\r\n const count = Number(result.stdout.trim());\r\n const parsed = Number.isFinite(count) ? count : null;\r\n this.aheadOfMain.set(key, parsed);\r\n return parsed;\r\n }\r\n}\r\n", "import { gitStatusShort } from \"./git.js\";\r\n\r\n/** Per-sweep memo so dependency-cache guards do not re-run git per cache dir. */\r\nexport class CleanupGitStatusCache {\r\n private readonly cache = new Map<string, string[]>();\r\n\r\n porcelain(worktreePath: string): string[] {\r\n const resolved = worktreePath;\r\n const cached = this.cache.get(resolved);\r\n if (cached !== undefined) return cached;\r\n const lines = gitStatusShort(resolved);\r\n this.cache.set(resolved, lines);\r\n return lines;\r\n }\r\n}\r\n", "import { deriveTerminalRunStatus } from \"./finalize.js\";\r\nimport type { HarnessRunRecord } from \"./run-store.js\";\r\n\r\n/** Per-sweep memo so worktree guards do not re-derive terminal status for every worker in a run. */\r\nexport class CleanupRunTerminalCache {\r\n private readonly cache = new Map<string, string | null>();\r\n\r\n derive(run: HarnessRunRecord): string | null {\r\n const cached = this.cache.get(run.id);\r\n if (cached !== undefined) return cached;\r\n const derived = deriveTerminalRunStatus(run);\r\n this.cache.set(run.id, derived);\r\n return derived;\r\n }\r\n}\r\n", "import type {\r\n CleanupActionKind,\r\n HarnessCleanupSummary,\r\n HarnessStorageSnapshotShape,\r\n} from \"./cleanup-types.js\";\r\n\r\nconst DEFAULT_SAMPLE_ACTIONS = 12;\r\nconst DEFAULT_SAMPLE_SKIPS = 8;\r\n\r\nexport interface CleanupCompactSummary {\r\n harnessRoot: string;\r\n scanRoots: string[];\r\n dryRun: boolean;\r\n execute: boolean;\r\n scannedAt: string;\r\n finalizedRuns: number;\r\n actionCount: number;\r\n actionKinds: Partial<Record<CleanupActionKind, number>>;\r\n totals: HarnessCleanupSummary[\"totals\"];\r\n storage?: HarnessStorageSnapshotShape;\r\n preservedLivePaths?: HarnessCleanupSummary[\"preservedLivePaths\"];\r\n removedRunDirectories?: number;\r\n sampleActions: Array<{\r\n kind: CleanupActionKind;\r\n path: string;\r\n skipReason?: string;\r\n bytes?: number | null;\r\n runId?: string;\r\n worker?: string;\r\n }>;\r\n sampleSkips: HarnessCleanupSummary[\"skips\"];\r\n}\r\n\r\nfunction tallyActionKinds(actions: HarnessCleanupSummary[\"actions\"]): Partial<Record<CleanupActionKind, number>> {\r\n const counts: Partial<Record<CleanupActionKind, number>> = {};\r\n for (const action of actions) {\r\n counts[action.kind] = (counts[action.kind] ?? 0) + 1;\r\n }\r\n return counts;\r\n}\r\n\r\n/** Operator-facing rollup \u2014 bounded samples, no per-path megabyte JSON dumps. */\r\nexport function buildCleanupCompactSummary(\r\n summary: HarnessCleanupSummary,\r\n options: { maxSampleActions?: number; maxSampleSkips?: number } = {},\r\n): CleanupCompactSummary {\r\n const maxActions = options.maxSampleActions ?? DEFAULT_SAMPLE_ACTIONS;\r\n const maxSkips = options.maxSampleSkips ?? DEFAULT_SAMPLE_SKIPS;\r\n\r\n return {\r\n harnessRoot: summary.harnessRoot,\r\n scanRoots: summary.scanRoots,\r\n dryRun: summary.dryRun,\r\n execute: summary.execute,\r\n scannedAt: summary.scannedAt,\r\n finalizedRuns: summary.finalizedRuns.length,\r\n actionCount: summary.actions.length,\r\n actionKinds: tallyActionKinds(summary.actions),\r\n totals: summary.totals,\r\n ...(summary.storage ? { storage: summary.storage } : {}),\r\n ...(summary.preservedLivePaths?.length ? { preservedLivePaths: summary.preservedLivePaths } : {}),\r\n ...(summary.removedRunDirectories != null ? { removedRunDirectories: summary.removedRunDirectories } : {}),\r\n sampleActions: summary.actions.slice(0, maxActions).map((action) => ({\r\n kind: action.kind,\r\n path: action.path,\r\n ...(action.skipReason ? { skipReason: action.skipReason } : {}),\r\n ...(action.bytes != null ? { bytes: action.bytes } : {}),\r\n ...(action.runId ? { runId: action.runId } : {}),\r\n ...(action.worker ? { worker: action.worker } : {}),\r\n })),\r\n sampleSkips: summary.skips.slice(0, maxSkips),\r\n };\r\n}\r\n"],
|
|
5
|
-
"mappings": ";;;;;;AAAA,SAAS,YAAY,WAAW,cAAc,aAAa,UAAU,qBAAqB;AAC1F,OAAO,UAAU;AAEV,SAAS,KAAK,SAAwB;AAC3C,UAAQ,MAAM,OAAO;AACrB,UAAQ,KAAK,CAAC;AAChB;AAGO,SAAS,mBAAsD,MAAY;AAChF,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,SAAO,EAAE,aAAa,MAAM,GAAG,KAAK;AACtC;AAOO,SAAS,SAAS,MAAuB;AAC9C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAY,MAAc,UAAiB;AACzD,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAAA,EAC9C,SAAS,OAAO;AACd,QAAI,UAAU,SAAS,EAAG,QAAO;AACjC,SAAK,kBAAkB,IAAI,KAAM,MAAgB,OAAO,EAAE;AAAA,EAC5D;AACF;AAEO,SAAS,UAAU,MAAc,OAAsB;AAC5D,YAAU,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,gBAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,CAAI;AAC3D;AAEO,SAAS,SAAS,OAAmC;AAC1D,SACE,OAAO,SAAS,EAAE,EACf,YAAY,EACZ,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,YAAY,EAAE,KAAK;AAElC;AAoBO,SAAS,SAAS,MAAsB;AAC7C,MAAI;AACF,WAAO,SAAS,IAAI,EAAE;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,MAA6B;AACrD,MAAI;AACF,WAAO,SAAS,IAAI,EAAE,MAAM,YAAY;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,MAAc,OAAuB;AAC5D,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,OAAO,aAAa,MAAM,MAAM;AACtC,SAAO,KAAK,MAAM,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,IAAI;AACjD;AAsBO,SAAS,WAAW,KAAkC;AAC3D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUO,SAAS,UAAU,QAAyD;AACjF,MAAI,OAAsB;AAC1B,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,MAAO;AACZ,UAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,QAAI,OAAO,SAAS,EAAE,KAAK,KAAK,QAAQ;AACtC,eAAS;AACT,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,QAAQ,IAAoB;AAC1C,SAAO,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,GAAI,CAAC;AACzD;AAhJA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAKa,2BAiCP;AAtCN;AAAA;AAAA;AAKO,IAAM,4BAA4B;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,IAAM,oBAAoB,IAAI,IAAY,yBAAyB;AAAA;AAAA;;;ACtCnE,SAAS,iBAAiB;AAQnB,SAAS,IAAI,KAAa,MAAgB,UAAsB,CAAC,GAAW;AACjF,QAAM,MAAM;AAAA,IACV;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,KAAK,UAAU,OAAgB,CAAC;AAAA,EACvD;AACA,MAAI,IAAI,WAAW,KAAK,CAAC,QAAQ,cAAc;AAC7C,UAAM,UAAU,OAAO,KAAK,KAAK,GAAG,CAAC,YAAY,IAAI,UAAU,IAAI,MAAM;AACzE,QAAI,QAAQ,WAAY,OAAM,IAAI,MAAM,OAAO;AAC/C,SAAK,OAAO;AAAA,EACd;AACA,SAAO,IAAI,UAAU;AACvB;AAMO,SAAS,eAAe,cAAgC;AAC7D,SAAO,IAAI,cAAc,CAAC,UAAU,SAAS,GAAG,EAAE,cAAc,KAAK,CAAC,EACnE,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACnB;AASO,SAAS,WAAW,KAAa,MAAkC;AACxE,MAAI;AACF,UAAM,MAAM;AAAA,MACZ;AAAA,MACA;AAAA,MACA,mBAAmB,EAAE,KAAK,UAAU,OAAgB,CAAC;AAAA,IACvD;AACE,WAAO;AAAA,MACL,QAAQ,IAAI;AAAA,MACZ,QAAQ,IAAI,UAAU;AAAA,MACtB,QAAQ,IAAI,UAAU;AAAA,MACtB,OAAO,IAAI,QAAQ,IAAI,MAAM,UAAU;AAAA,IACzC;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,OAAQ,MAAgB;AAAA,IAC1B;AAAA,EACF;AACF;AAEO,SAAS,cACd,KACA,UACA,YACsD;AACtD,QAAM,MAAM,WAAW,KAAK,CAAC,cAAc,iBAAiB,UAAU,UAAU,CAAC;AACjF,MAAI,IAAI,WAAW,EAAG,QAAO,EAAE,YAAY,MAAM,OAAO,KAAK;AAC7D,MAAI,IAAI,WAAW,EAAG,QAAO,EAAE,YAAY,OAAO,OAAO,KAAK;AAC9D,SAAO,EAAE,YAAY,MAAM,OAAO,IAAI,SAAS,IAAI,UAAU,IAAI,UAAU,cAAc,IAAI,MAAM,GAAG;AACxG;AAsBO,SAAS,mBAAmB,cAAsB,gBAA6C,eAA4B;AAChI,QAAM,UACJ,OAAO,kBAAkB,WAAW,EAAE,MAAM,cAAc,IAAI;AAChE,QAAM,YAAY,QAAQ,YAAY,KAAK,KAAK,QAAQ,MAAM,KAAK,KAAK;AACxE,QAAM,mBAAmB,QAAQ,YAAY,KAAK,KAAK;AAEvD,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAgB,WAAW,uBAAuB;AAAA,EAC3D;AAEA,QAAM,OAAO,WAAW,cAAc,CAAC,aAAa,MAAM,CAAC;AAC3D,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,gBAAgB,WAAW,KAAK,SAAS,KAAK,UAAU,KAAK,UAAU,wBAAwB;AAAA,EACxG;AAEA,MAAI;AACJ,MAAI,kBAAkB;AACpB,cAAU;AAAA,EACZ,OAAO;AACL,UAAM,WAAW,WAAW,cAAc,CAAC,aAAa,SAAS,CAAC;AAClE,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,QACL;AAAA,QACA,SAAS,SAAS,SAAS,UAAU,SAAS,UAAU,qBAAqB,SAAS;AAAA,QACtF,KAAK,OAAO,KAAK;AAAA,MACnB;AAAA,IACF;AACA,cAAU,SAAS,OAAO,KAAK;AAAA,EACjC;AAEA,QAAM,UAAU,KAAK,OAAO,KAAK;AACjC,MAAI,YAAY,SAAS;AACvB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,sBAAsB;AAAA,MACtB,sBAAsB;AAAA,MACtB,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,uBAAuB,cAAc,cAAc,SAAS,OAAO;AACzE,QAAM,uBAAuB,cAAc,cAAc,SAAS,OAAO;AACzE,QAAM,QAAQ,qBAAqB,SAAS,qBAAqB,SAAS;AAC1E,MAAI,qBAAqB,cAAc,QAAQ,qBAAqB,cAAc,MAAM;AACtF,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,MACV,sBAAsB,qBAAqB;AAAA,MAC3C,sBAAsB,qBAAqB;AAAA,MAC3C,UAAU;AAAA,MACV,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,WAAgC,qBAAqB,aACvD,UACA,qBAAqB,aACnB,WACA;AAEN,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,sBAAsB,qBAAqB;AAAA,IAC3C,sBAAsB,qBAAqB;AAAA,IAC3C;AAAA,IACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,EAC3B;AACF;AAEA,SAAS,gBAAgB,MAAc,OAAe,OAAsB,MAAmB;AAC7F,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,UAAU;AAAA,IACV;AAAA,EACF;AACF;AAtLA;AAAA;AAAA;AACA;AAuLA;AAAA;AAAA;;;ACxLA,SAAS,eAAe;AACxB,OAAOA,WAAU;AAEV,SAAS,eAAe,OAAuB;AACpD,MAAI,UAAU,IAAK,QAAO,QAAQ;AAClC,MAAI,MAAM,WAAW,IAAI,KAAK,MAAM,WAAW,KAAK,GAAG;AACrD,WAAOA,MAAK,KAAK,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,OAAuB;AACrD,SAAOA,MAAK,QAAQ,eAAe,KAAK,CAAC;AAC3C;AAbA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAIA;AACA;AAAA;AAAA;;;ACLA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,cAAAC,aAAY,gBAAAC,eAAc,kBAAkB;AA4C9C,SAAS,YAAqB;AACnC,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,aAAW,SAAS,CAAC,8BAA8B,eAAe,GAAG;AACnE,QAAI;AACF,UAAI,CAACD,YAAW,KAAK,EAAG;AACxB,YAAM,OAAOC,cAAa,OAAO,MAAM;AACvC,UAAI,iBAAiB,KAAK,IAAI,EAAG,QAAO;AAAA,IAC1C,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAuBO,SAAS,mBACd,UAAqC,CAAC,GACb;AACzB,QAAM,MAAM,QAAQ,aAAa,SAAY,UAAU,IAAI,QAAQ;AACnE,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAMC,SACJ,QAAQ,cAAc,KAAK,KAC3B,QAAQ,IAAI,uBAAuB,KAAK,KACxC;AACF,QAAM,iBAAiB,QAAQ,wBAAwB;AACvD,QAAM,qBACJ,QAAQ,4BAA4B;AAEtC,QAAM,SAAS,QAAQ,UAAU;AACjC,MAAI;AACJ,MAAI;AACF,YAAQ,OAAOA,MAAI;AAAA,EACrB,SAAS,OAAO;AACd,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAAA;AAAA,MACA,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA,QAAQ,qCAAqCA,MAAI,KAAM,MAAgB,OAAO;AAAA,MAC9E,YAAa,MAAgB;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,YAAY,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,KAAK;AAC3D,QAAM,aAAa,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,KAAK;AAC5D,QAAM,cAAc,aAAa,KAAM,aAAa,aAAa,aAAc,MAAM;AACrF,QAAM,UAAU,YAAY;AAC5B,QAAM,eAAe,YAAY;AACjC,QAAM,KAAK,CAAC,WAAW,CAAC;AAExB,QAAM,WAAW,aAAa,OAAO,OAAO,OAAO,QAAQ,CAAC;AAC5D,MAAI,SAAwB;AAC5B,MAAI,CAAC,IAAI;AACP,UAAM,MAAM,eAAe,aAAa;AACxC,aACE,qBAAqBA,MAAI,OAAO,GAAG,KAAK,OAAO,gBACzC,eAAe,qBAAqB,kBAAkB,OAAO,OAAO,IAAI,uCAC9C,0BAA0B,CAAC;AAAA,EAC/D;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACF;AAOO,SAAS,4BAAoC;AAClD,SACE;AAMJ;AA1JA,IAea,kCAIA,sCAEA;AArBb;AAAA;AAAA;AAeO,IAAM,mCAAmC,KAAK,OAAO,OAAO;AAI5D,IAAM,uCAAuC,KAAK,OAAO,OAAO;AAEhE,IAAM,yBAAyB;AAAA;AAAA;;;ACrBtC,SAAS,cAAAC,mBAAkB;AAyBpB,SAAS,sBAAsB,QAA8B,CAAC,GAA8B;AACjG,QAAMC,SAAO,MAAM,UAAU,KAAK,KAAK;AACvC,QAAM,iBAAiB,MAAM,qBAAqB;AAClD,QAAM,qBAAqB,MAAM,yBAAyB;AAC1D,QAAM,iBAAiB,MAAM,sBAAsB;AACnD,QAAM,qBAAqB,MAAM,0BAA0B;AAE3D,QAAM,QAAQD,YAAWC,MAAI;AAC7B,QAAM,YAAY,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,KAAK;AAC3D,QAAM,aAAa,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,KAAK;AAC5D,QAAM,cAAc,aAAa,KAAM,aAAa,aAAa,aAAc,MAAM;AACrF,QAAM,UAAU,YAAY;AAC5B,QAAM,eAAe,YAAY;AACjC,QAAM,UAAU,cAAc;AAC9B,QAAM,cAAc,cAAc;AAClC,QAAM,UAAU,CAAC,WAAW,CAAC,gBAAgB,CAAC,WAAW,CAAC;AAI1D,QAAM,UAAmC,MAAM,mBAC3C,OACA,mBAAmB,MAAM,OAAO;AAEpC,QAAM,KAAK,YAAY,UAAU,QAAQ,KAAK;AAE9C,MAAI,SAAwB;AAC5B,MAAI,CAAC,IAAI;AACP,aAAS;AAAA,MACP,eAAe,6BAA6B,kBAAkB,WAAW;AAAA,MACzE,UAAU,4BAA4B,cAAc,WAAW;AAAA,MAC/D,cAAc,+BAA+B,kBAAkB,MAAM;AAAA,MACrE,UAAU,0BAA0B,cAAc,MAAM;AAAA,MACxD,WAAW,CAAC,QAAQ,KAAK,QAAQ,SAAS;AAAA,IAC5C,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACd;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA5EA,IAQM,yBACA,6BACA,0BACA;AAXN;AAAA;AAAA;AAEA;AAMA,IAAM,0BAA0B,KAAK,OAAO,OAAO;AACnD,IAAM,8BAA8B,KAAK,OAAO,OAAO;AACvD,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AAAA;AAAA;;;ACXtC,SAAS,cAAAC,aAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,WAAU;AAgBV,SAAS,WAAW;AACzB,SAAO,gBAAgB;AACzB;AAYO,SAAS,iBAAqC;AACnD,QAAM,EAAE,QAAQ,IAAI,SAAS;AAC7B,SAAO,iBAAiB,OAAO;AACjC;AAEO,SAAS,6BAA6B,aAAyC;AACpF,SAAO,iBAAiB,eAAe,WAAW,CAAC;AACrD;AAEA,SAAS,oBAAoB,YAA6B;AACxD,MAAI;AACF,WAAOD,UAAS,UAAU,EAAE,YAAY;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,SAAqC;AAC7D,MAAI,CAACF,YAAW,OAAO,EAAG,QAAO,CAAC;AAClC,QAAM,OAA2B,CAAC;AAClC,aAAW,SAASC,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACjE,QAAI,MAAM,SAAS,OAAQ;AAC3B,UAAMG,UAASD,MAAK,KAAK,SAAS,MAAM,IAAI;AAC5C,QAAI,CAAC,oBAAoBC,OAAM,EAAG;AAClC,UAAM,MAAM;AAAA,MACVD,MAAK,KAAKC,SAAQ,UAAU;AAAA,MAC5B;AAAA,IACF;AACA,QAAI,KAAK,GAAI,MAAK,KAAK,GAAG;AAAA,EAC5B;AACA,SAAO;AACT;AASO,SAAS,QAAQ,KAA6B;AACnD,QAAM,EAAE,QAAQ,IAAI,SAAS;AAC7B,YAAUD,MAAK,KAAK,OAAW,SAAS,IAAI,EAAE,GAAG,UAAU,GAAG,GAAG;AACnE;AAOO,SAAS,aAAa,IAAoB;AAC/C,QAAM,EAAE,YAAY,IAAI,SAAS;AACjC,SAAO,eAAe,aAAa,EAAE;AACvC;AAEO,SAAS,eAAe,aAAqB,IAAoB;AACtE,SAAO,OAAW,eAAe,WAAW,GAAG,SAAS,EAAE,CAAC;AAC7D;AAxFA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;;;ACHA,SAAS,cAAAE,aAAY,eAAAC,oBAAmB;AACxC,OAAOC,WAAU;AAYV,SAAS,mBAAmB,KAAiC;AAClE,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,QAAQ,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC,GAAG;AACjD,UAAM,IAAI,SAAS,IAAI,CAAC;AAAA,EAC1B;AACA,QAAM,aAAaA,MAAK,KAAK,aAAa,IAAI,EAAE,GAAG,SAAS;AAC5D,MAAI,CAACF,YAAW,UAAU,EAAG,QAAO,CAAC,GAAG,KAAK;AAC7C,aAAW,SAASC,aAAY,YAAY,EAAE,eAAe,KAAK,CAAC,GAAG;AACpE,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,UAAM,IAAI,SAAS,MAAM,IAAI,CAAC;AAAA,EAChC;AACA,SAAO,CAAC,GAAG,KAAK;AAClB;AAzBA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;;;ACDA,SAAS,mBAAmB,MAA8C;AACxE,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAQ,WAAW,GAAG,EAAG,QAAO;AACrC,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,QAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,MAA8C;AAC7E,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS,mBAAmB,OAAO;AACzC,MAAI,OAAQ,QAAO;AAEnB,QAAM,aAAwC,CAAC;AAC/C,QAAM,UAAU;AAChB,MAAI;AACJ,UAAQ,aAAa,QAAQ,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,YAAY,mBAAmB,WAAW,CAAC,KAAK,EAAE;AACxD,QAAI,UAAW,YAAW,KAAK,SAAS;AAAA,EAC1C;AAEA,QAAM,aAAa,QAAQ,QAAQ,GAAG;AACtC,QAAM,YAAY,QAAQ,YAAY,GAAG;AACzC,MAAI,cAAc,KAAK,YAAY,YAAY;AAC7C,UAAM,QAAQ,mBAAmB,QAAQ,MAAM,YAAY,YAAY,CAAC,CAAC;AACzE,QAAI,MAAO,YAAW,KAAK,KAAK;AAAA,EAClC;AAEA,SAAO,WAAW,SAAS,IAAI,WAAW,WAAW,SAAS,CAAC,IAAK;AACtE;AAMO,SAAS,oCACd,KACS;AACT,QAAM,WAAW,IAAI,eAAe,IAAI;AACxC,MAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,QAAI,OAAO,aAAa,UAAU;AAChC,YAAME,YAAW,wBAAwB,QAAQ;AACjD,aAAOA,cAAa,SAAS,KAAK,KAAK;AAAA,IACzC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,KAAK,IAAI;AACvE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,WAAW,wBAAwB,OAAO;AAChD,MAAI,SAAU,QAAO;AAErB,SAAO;AACT;AA/DA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AA2BlC,SAAS,yBAAyB,OAA2C;AAClF,SAAO,UAAU;AACnB;AAOO,SAAS,iCAAiC,WAAqC;AACpF,MAAI,CAAC,yBAAyB,UAAU,kBAAkB,EAAG,QAAO;AACpE,MAAI,UAAU,wBAAwB,UAAa,UAAU,wBAAwB,MAAM;AACzF,WAAO,UAAU;AAAA,EACnB;AACA,QAAM,UAAU,UAAU,sBAAsB,KAAK;AACrD,SAAO,WAAW;AACpB;AAEO,SAAS,eAAe,MAA+B;AAC5D,QAAM,SAA0B;AAAA,IAC9B,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,kBAAkB;AAAA,IAClB,oBAAoB,CAAC;AAAA,IACrB,yBAAyB;AAAA,IACzB,gBAAgB,CAAC;AAAA,EACnB;AACA,MAAI,CAACD,YAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,cAAc,KAAK,IAAI,IAAI;AACjC,QAAM,YAAY,IAAI,KAAK,WAAW,EAAE,YAAY;AACpD,QAAM,QAAQC,cAAa,MAAM,MAAM,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACnE,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,SAAS,IAAI;AAC3B,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG;AACjE,UAAM,MAAM;AACZ,WAAO;AACP,QAAI,IAAI,IAAI;AACV,YAAM,KAAK,OAAO,IAAI,EAAE;AACxB,YAAM,OAAO,KAAK,MAAM,EAAE;AAC1B,UAAI,OAAO,SAAS,IAAI,KAAK,OAAO,aAAa;AAC/C,eAAO,mBAAmB,KAAK;AAAA,UAC7B,MAAM;AAAA,UACN,YAAY;AAAA,UACZ;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AACL,eAAO,kBAAkB;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,IAAI,UAAU,UAAa,IAAI,UAAU,KAAM,QAAO,qBAAqB,OAAO,IAAI,KAAK;AAC/F,QAAI,IAAI,YAAY,UAAa,IAAI,YAAY,KAAM,QAAO,uBAAuB,OAAO,IAAI,OAAO;AACvG,QAAI,yBAAyB,OAAO,kBAAkB,GAAG;AACvD,aAAO,sBAAsB,oCAAoC,GAAG;AAAA,IACtE;AACA,WAAO,mBAAmB,IAAI,UAAU,OAAO,IAAI,OAAO,IAAI;AAC9D,QAAI,IAAI,uBAAuB,OAAO,IAAI,wBAAwB,YAAY,CAAC,MAAM,QAAQ,IAAI,mBAAmB,GAAG;AACrH,aAAO,0BAA0B,IAAI;AAAA,IACvC;AACA,QAAI,MAAM,QAAQ,IAAI,UAAU,GAAG;AACjC,aAAO,iBAAiB,IAAI,WAAW;AAAA,QACrC,CAACC,WACC,CAAC,CAACA,UACF,OAAOA,WAAU,YACjB,OAAQA,OAA+C,UAAU;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAlGA,IAwBM;AAxBN;AAAA;AAAA;AACA;AACA;AAsBA,IAAM,2BAA2B;AAAA;AAAA;;;ACcjC,SAAS,WAAW,OAA0C;AAC5D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK;AACvC,SAAO,KAAK,QAAQ,WAAW,EAAE,EAAE,YAAY;AACjD;AAEA,SAAS,gBAAgB,OAAyB;AAChD,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU;AACd,MAAI;AACJ,MAAI,UAAU;AACd,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS;AACX,iBAAW;AACX,gBAAU;AACV;AAAA,IACF;AACA,QAAI,SAAS,MAAM;AACjB,gBAAU;AACV;AAAA,IACF;AACA,QAAI,OAAO;AACT,UAAI,SAAS,MAAO,SAAQ;AAAA,UACvB,YAAW;AAChB;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR;AAAA,IACF;AACA,QAAI,KAAK,KAAK,IAAI,GAAG;AACnB,UAAI,SAAS;AACX,cAAM,KAAK,OAAO;AAClB,kBAAU;AAAA,MACZ;AACA;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,MAAI,QAAS,OAAM,KAAK,OAAO;AAC/B,SAAO;AACT;AAEA,SAAS,SAAS,MAAyB;AACzC,QAAM,MAAM,WAAW,KAAK,CAAC,CAAC;AAC9B,SAAO,QAAQ,OAAO,YAAY,IAAI,GAAG,CAAC;AAC5C;AAEO,SAAS,yBAAyB,QAAqC;AAC5E,MAAI,CAAC,UAAU,OAAO,SAAS,GAAG,KAAK,OAAO,SAAS,GAAG,EAAG,QAAO;AACpE,SAAO,8CAA8C,KAAK,MAAM;AAClE;AAGO,SAAS,uBAAuB,QAAqC;AAC1E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,IAAI,OAAO,KAAK;AACtB,SAAO,EAAE,WAAW,GAAG,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,EAAE,SAAS,KAAK;AACnE;AAEA,SAAS,eAAe,OAAuB;AAC7C,MAAI,CAAC,MAAM,WAAW,SAAS,EAAG,QAAO;AACzC,QAAM,QAAQ,MAAM,MAAM,UAAU,MAAM;AAC1C,MAAI,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,SAAS,KAAK,GAAG;AAC3E,WAAO,UAAU,KAAK;AAAA,EACxB;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAA0B;AACrD,QAAM,aAAuB,CAAC;AAC9B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,CAAC,MAAO;AACZ,QAAI,UAAU,MAAM;AAClB,iBAAW,KAAK,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC;AACpC;AAAA,IACF;AACA,QAAI,MAAM,WAAW,GAAG,GAAG;AACzB,UAAI,MAAM,SAAS,GAAG,EAAG;AACzB,UAAI,mBAAmB,IAAI,KAAK,EAAG,MAAK;AACxC;AAAA,IACF;AACA,eAAW,KAAK,KAAK;AAAA,EACvB;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,MAAsD;AACpF,MAAI,UAAU;AACd,QAAM,MAAM,KAAK,IAAI,CAAC,UAAU;AAC9B,UAAM,QAAQ,eAAe,KAAK;AAClC,QAAI,UAAU,MAAO,WAAU;AAC/B,WAAO;AAAA,EACT,CAAC;AACD,QAAM,aAAa,oBAAoB,GAAG;AAC1C,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,CAAC,SAAS,MAAM,IAAI;AAC1B,QAAI,yBAAyB,MAAM,GAAG;AACpC,aAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,MAAM,QAAQ,SAAS,GAAG,GAAG,SAAS,KAAK;AAAA,IAC7E;AAAA,EACF;AACA,SAAO,EAAE,MAAM,KAAK,QAAQ;AAC9B;AAEO,SAAS,2BAA2B,SAAwD;AACjG,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,CAAC,QAAS,QAAO,EAAE,SAAS,SAAS,SAAS,MAAM;AACxD,QAAM,SAAS,QAAQ,SAAS,IAAI,IAAI,SAAS,QAAQ,SAAS,IAAI,IAAI,SAAS;AACnF,QAAM,SAAS,QAAQ,MAAM,sBAAsB;AACnD,MAAI,UAAU;AACd,QAAM,mBAAmB,OAAO,IAAI,CAAC,UAAU;AAC7C,UAAM,OAAO,gBAAgB,MAAM,KAAK,CAAC;AACzC,QAAI,CAAC,KAAK,UAAU,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5C,UAAM,aAAa,gBAAgB,IAAI;AACvC,QAAI,WAAW,SAAS;AACtB,gBAAU;AACV,aAAO,WAAW,KAAK,KAAK,GAAG;AAAA,IACjC;AACA,WAAO;AAAA,EACT,CAAC;AACD,MAAI,CAAC,QAAS,QAAO,EAAE,SAAS,SAAS,SAAS,MAAM;AACxD,SAAO,EAAE,SAAS,iBAAiB,KAAK,MAAM,GAAG,SAAS,KAAK;AACjE;AAEO,SAAS,kBAAkB,MAAqD;AACrF,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,QAAM,gBAAgB,KAAK,MAAM,+CAA+C;AAChF,MAAI,eAAe;AACjB,WAAO,EAAE,SAAS,cAAc,CAAC,GAAG,QAAQ,cAAc,CAAC,GAAG,KAAK,EAAE;AAAA,EACvE;AACA,QAAM,QAAQ,KAAK,MAAM,iCAAiC;AAC1D,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,SAAO,EAAE,SAAS,MAAM,CAAC,GAAG,QAAQ,MAAM,CAAC,GAAG,KAAK,EAAE;AACvD;AAEO,SAAS,uBAAuB,MAAiC;AACtE,QAAM,EAAE,SAAS,OAAO,IAAI,kBAAkB,IAAI;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE,MAAM,kBAAkB;AAC/C,MAAI,uBAAuB,MAAM,GAAG;AAClC,WAAO,EAAE,MAAM,qBAAqB,SAAS,OAAO;AAAA,EACtD;AACA,MAAI,yBAAyB,MAAM,GAAG;AACpC,WAAO,EAAE,MAAM,aAAa,SAAS,OAAO;AAAA,EAC9C;AACA,SAAO,EAAE,MAAM,mBAAmB,SAAS,OAAO;AACpD;AAEO,SAAS,0BAA0B,MAA4D;AACpG,QAAM,EAAE,SAAS,OAAO,IAAI,kBAAkB,IAAI;AAClD,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,uBAAuB,MAAM,GAAG;AAClC,UAAM,OAAO,GAAG,OAAQ,KAAK,CAAC;AAC9B,WAAO;AAAA,MACL,SAAS,OAAO,OAAO,SAAS,IAAI;AAAA,MACpC,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,UAAU,yBAAyB,MAAM,GAAG;AAC9C,WAAO;AAAA,MACL,SAAS,SAAS,MAAM,KAAK,OAAO;AAAA,MACpC,SAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,KAAuC;AAC9E,MACE,IAAI,SAAS,eACb,IAAI,SAAS,SAAS,kBAAkB,KACxC,IAAI,WAAW,gBACf;AACA,WACE;AAAA,EAGJ;AACA,MAAI,IAAI,SAAS,eAAe,IAAI,WAAW,IAAI,QAAQ;AACzD,WAAO,gBAAgB,IAAI,MAAM,KAAK,IAAI,OAAO,+CAA+C,IAAI,MAAM;AAAA,EAC5G;AACA,MAAI,IAAI,SAAS,uBAAuB,IAAI,SAAS;AACnD,UAAM,OAAO,IAAI,SAAS,GAAG,IAAI,OAAO,KAAK,CAAC,QAAQ;AACtD,WACE,uBAAuB,IAAI,UAAU,eAAe,6CACvC,IAAI,OAAO,SAAS,IAAI;AAAA,EAEzC;AACA,MAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS;AAC5C,WAAO,mBAAmB,IAAI,OAAO,+FAA+F,IAAI,OAAO;AAAA,EACjJ;AACA,SAAO;AACT;AAGO,SAAS,8BAA8B,MAA6B;AACzE,QAAM,QAAQ,KAAK,MAAM,gEAAgE;AACzF,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,WAAW,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,GAAG,KAAK,CAAC;AACpD;AAEO,SAAS,0BAA0B,OAIxB;AAChB,QAAM,OACJ,MAAM,MAAM,KAAK,MAChB,MAAM,UAAU,8BAA8B,MAAM,OAAO,IAAI,SAChE;AACF,MAAI,MAAM;AACR,UAAM,MAAM,uBAAuB,IAAI;AACvC,UAAM,WAAW,yBAAyB,GAAG;AAC7C,QAAI,SAAU,QAAO;AACrB,UAAM,aAAa,0BAA0B,IAAI;AACjD,QAAI,YAAY,SAAS;AACvB,aAAO,oDAAoD,WAAW,OAAO;AAAA,IAC/E;AAAA,EACF;AACA,MAAI,MAAM,WAAW,oBAAoB,KAAK,MAAM,OAAO,GAAG;AAC5D,UAAM,aAAa,2BAA2B,MAAM,OAAO;AAC3D,QAAI,WAAW,SAAS;AACtB,aAAO,+CAA+C,WAAW,OAAO;AAAA,IAC1E;AACA,QAAI,MAAM,aAAa,GAAG;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AA5QA,IAOM,aACA;AARN;AAAA;AAAA;AAOA,IAAM,cAAc,oBAAI,IAAI,CAAC,MAAM,WAAW,MAAM,CAAC;AACrD,IAAM,qBAAqB,oBAAI,IAAI;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA;AAAA;;;ACeD,SAAS,KAAK,MAAc,MAAM,KAAa;AAC7C,QAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC3C,SAAO,IAAI,SAAS,MAAM,GAAG,IAAI,MAAM,GAAG,MAAM,CAAC,CAAC,WAAM;AAC1D;AAEA,SAAS,kBAAkB,MAA8B;AACvD,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,QAAI;AACF,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,QAAM,MAAM,QAAQ,YAAY,GAAG;AACnC,MAAI,SAAS,KAAK,MAAM,OAAO;AAC7B,QAAI;AACF,aAAO,KAAK,MAAM,QAAQ,MAAM,OAAO,MAAM,CAAC,CAAC;AAAA,IACjD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEO,SAAS,wBAAwB,QAAyD;AAC/F,QAAM,OAAO,OAAO;AACpB,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAM,MAAM,CAAC,QAAiB,OAAO,KAAK,GAAG,MAAM,WAAW,KAAK,GAAG,IAAI;AAC1E,QAAM,UAA2B;AAAA,IAC/B,MAAM,IAAI,MAAM;AAAA,IAChB,KAAK,IAAI,KAAK;AAAA,IACd,UAAU,IAAI,UAAU;AAAA,IACxB,MAAM,IAAI,MAAM;AAAA,IAChB,UAAU,IAAI,UAAU;AAAA,IACxB,OAAO,IAAI,OAAO;AAAA,EACpB;AACA,MACE,OAAO,KAAK,UAAU,YACtB,CAAC,QAAQ,YACT,CAAC,QAAQ,QACT,CAAC,QAAQ,YACT,CAAC,QAAQ,OACT,CAAC,QAAQ,MACT;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAgC;AAC9D,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,SAAU,OAAM,KAAK,GAAG,MAAM,QAAQ,WAAW;AAC3D,MAAI,MAAM,KAAM,OAAM,KAAK,GAAG,MAAM,IAAI,OAAO;AAC/C,MAAI,MAAM,SAAU,OAAM,KAAK,GAAG,MAAM,QAAQ,WAAW;AAC3D,MAAI,MAAM,IAAK,OAAM,KAAK,GAAG,MAAM,GAAG,MAAM;AAC5C,MAAI,MAAM,KAAM,OAAM,KAAK,GAAG,MAAM,IAAI,OAAO;AAC/C,QAAM,YAAY,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;AACpD,SAAO,cAAc,MAAM,KAAK,gBAAgB,MAAM,UAAU,IAAI,MAAM,KAAK,KAAK,SAAS;AAC/F;AAEA,SAAS,sBAAsB,QAAiC,QAAwB;AACtF,QAAM,MAAM,OAAO;AACnB,MAAI,SAAS,GAAG,GAAG;AACjB,UAAM,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,KAAK,IAAI;AACvE,UAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,KAAK,KAAK,IAAI;AAC9D,QAAI,QAAS,QAAO,OAAO,GAAG,IAAI,KAAK,OAAO,KAAK;AACnD,QAAI,KAAM,QAAO;AAAA,EACnB;AACA,QAAM,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,QAAQ,KAAK,IAAI;AAC5E,MAAI,OAAQ,QAAO;AACnB,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAS,QAAO,KAAK,QAAQ,MAAM,IAAI,EAAE,KAAK,OAAO,KAAK,SAAS,GAAG;AAC1E,SAAO;AACT;AAEO,SAAS,wBAAwB,OAIhB;AACtB,QAAM,WAAW,GAAG,MAAM,MAAM;AAAA,EAAK,MAAM,MAAM,GAAG,KAAK;AACzD,QAAM,SAAS,kBAAkB,QAAQ;AAEzC,MAAI,CAAC,UAAU,CAAC,SAAS,MAAM,GAAG;AAChC,UAAM,OAAO,KAAK,YAAY,QAAQ,MAAM,QAAQ,IAAI,GAAG;AAC3D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,MAAM;AAAA,MAChB,SAAS,+CAA+C,IAAI;AAAA,MAC5D,YAAY;AAAA,IACd;AAAA,EACF;AAEA,MAAI,SAAS,OAAO,KAAK,GAAG;AAC1B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,MAAM;AAAA,MAChB,SAAS,6BAA6B,sBAAsB,QAAQ,MAAM,MAAM,CAAC;AAAA,IACnF;AAAA,EACF;AAEA,QAAM,QAAQ,wBAAwB,MAAM;AAC5C,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,MAAM;AAAA,MAChB,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF;AAEA,MAAI,MAAM,aAAa,KAAK,MAAM,UAAU,GAAG;AAC7C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAM;AAAA,IAChB,SAAS,uBAAuB,KAAK;AAAA,IACrC;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,SAA0B;AACnD,SAAO,aAAa,KAAK,OAAO;AAClC;AAEA,SAAS,YAAY,SAA0B;AAC7C,SAAO,UAAU,KAAK,OAAO;AAC/B;AAEA,SAAS,kBAAkB,OAMH;AACtB,QAAM,YAAY,0BAA0B;AAAA,IAC1C,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,EAClB,CAAC;AAED,MAAI,MAAM,aAAa,GAAG;AACxB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,aAAa,GAAG;AACxB,UAAM,WAAW,MAAM,UAAU,MAAM,aAAa,KAAK;AACzD,QAAI,WAAW,iBAAiB,KAAK,OAAO,GAAG;AAC7C,YAAMC,QAAO,KAAK,SAAS,GAAG;AAC9B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,aAAa,4BAA4BA,KAAI;AAAA,MACxD;AAAA,IACF;AACA,UAAM,aAAa,2BAA2B,MAAM,OAAO;AAC3D,UAAM,QACJ,WAAW,WAAW,CAAC,YAAY,kBAAkB,WAAW,OAAO,QAAQ;AACjF,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SACE,aACA,gCAAgC,KAAK;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,OAAO,KAAK,MAAM,eAAe,MAAM,UAAU,MAAM,UAAU,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpG,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAM;AAAA,IAChB,SAAS,aAAa,wBAAwB,MAAM,QAAQ,MAAM,IAAI;AAAA,EACxE;AACF;AAEO,SAAS,4BAA4B,OAMpB;AACtB,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,cAAc,MAAM,qBAAqB;AAE/C,MAAI,kBAAkB,MAAM,OAAO,GAAG;AACpC,UAAM,OAAO,OAAO,KAAK,KAAK,YAAY,KAAK,KAAK,OAAO,KAAK;AAChE,WAAO,wBAAwB;AAAA,MAC7B,UAAU,MAAM;AAAA,MAChB,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,YAAY,MAAM,OAAO,GAAG;AAC9B,WAAO,kBAAkB;AAAA,MACvB,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,0BAA0B;AAAA,IAChD,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,EAClB,CAAC;AACD,MAAI,mBAAmB,MAAM,aAAa,GAAG;AAC3C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,MAAM;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,aAAa,GAAG;AACxB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,OAAO,KAAK,eAAe,UAAU,UAAU,QAAQ,MAAM,QAAQ,IAAI,GAAG;AAClF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAM;AAAA,IAChB,SAAS,wBAAwB,MAAM,QAAQ,MAAM,IAAI;AAAA,EAC3D;AACF;AAlSA,IAmCM,cACA,WACA;AArCN;AAAA;AAAA;AAOA;AA4BA,IAAM,eAAe;AACrB,IAAM,YAAY;AAClB,IAAM,mBAAmB;AAAA;AAAA;;;ACrCzB,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AAiBzC,SAAS,kBAAkB,OAAoD;AAC7E,QAAM,OAAO,MAAM;AACnB,SAAQ,MAAM,aAAa,MAAM,OAAO,OAAO,IAAI,KAAK,IAAI,EAAE,YAAY,IAAI;AAGhF;AAGA,SAAS,uBAAuB,UAA8D;AAC5F,MAAI,CAAC,SAAU,QAAO;AACtB,aAAW,OAAO,OAAO,KAAK,QAAQ,GAAG;AACvC,QAAI,IAAI,SAAS,UAAU,GAAG;AAC5B,YAAM,OAAO,IAAI,MAAM,GAAG,CAAC,WAAW,MAAM;AAC5C,aAAO,KAAK,SAAS,OAAO;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,QAAsB,OAAsC;AACtF,SAAO,cAAc,MAAM,UAAU,MAAM,WAAW,MAAM,mBAAmB;AAC/E,MAAI,MAAM,UAAU;AAClB,WAAO,QAAQ,OAAO,MAAM,UAAU,MAAM,oBAAoB,qBAAqB;AAAA,EACvF;AACF;AAEA,SAAS,4BACP,OACmG;AACnG,MAAI,MAAM,SAAS,eAAe,MAAM,YAAY,YAAa,QAAO;AACxE,QAAM,WACJ,MAAM,aAAa,OAAO,MAAM,cAAc,YAAY,CAAC,MAAM,QAAQ,MAAM,SAAS,IACnF,MAAM,YACP;AACN,QAAM,QAAQ,UAAU;AACxB,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,WAAW;AACjB,QAAM,OAAO,SAAS;AACtB,QAAM,UACJ,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,KAAK,OAAQ,KAAiC,YAAY,WAC7G,OAAQ,KAAiC,OAAO,IAChD;AACN,QAAM,SAAS,SAAS;AACxB,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO;AAC3E,QAAM,OAAQ,OAAmC,WAAY,OAAmC;AAChG,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG,QAAO;AACrE,QAAM,MAAM;AACZ,QAAM,WAAW,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS;AAAA,IACtD,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS;AAAA,IACtD,aAAa,OAAO,IAAI,sBAAsB,WAAW,IAAI,oBAAoB;AAAA,EACnF;AACF;AAEA,SAAS,kBAAkB,QAAsB,SAAoC;AACnF,MAAI,QAAQ,SAAS,aAAa,QAAQ,SAAS,oBAAqB;AACxE,SAAO,mBAAmB;AAC5B;AAOO,SAAS,mBAAmB,MAA4B;AAC7D,QAAM,SAAuB;AAAA,IAC3B,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,OAAO;AAAA,IACP,kBAAkB;AAAA,EACpB;AACA,MAAI,CAACD,YAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,QAAQC,cAAa,MAAM,MAAM,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACnE,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,SAAS,IAAI;AAC3B,QAAI,CAAC,MAAO;AACZ,UAAM,KAAK,kBAAkB,KAAK;AAClC,QAAI,IAAI;AACN,aAAO,iBAAiB;AACxB,aAAO,cAAc;AAAA,IACvB;AACA,QACE,MAAM,SAAS,kBACf,MAAM,SACN,OAAO,MAAM,UAAU,YACtB,MAAM,MAAkC,SAAS,uBAClD;AACA,YAAM,QAAS,MAAM,MAAkC;AACvD,UAAI,OAAO,SAAS,WAAY,QAAO,cAAc,OAAO,MAAM,QAAQ,MAAM;AAAA,IAClF;AACA,QAAI,MAAM,SAAS,eAAe,MAAM,WAAW,OAAO,MAAM,YAAY,UAAU;AACpF,YAAM,UAAW,MAAM,QAAoC;AAC3D,UAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,cAAM,OAAO,QAAQ,KAAK,CAAC,SAAS,MAAM,SAAS,UAAU;AAC7D,YAAI,KAAM,QAAO,cAAc,OAAO,KAAK,QAAQ,OAAO,WAAW;AAAA,MACvE;AAAA,IACF;AACA,QAAI,MAAM,SAAS,eAAe,MAAM,YAAY,WAAW;AAC7D,YAAM,WACJ,MAAM,aAAa,OAAO,MAAM,cAAc,YAAY,CAAC,MAAM,QAAQ,MAAM,SAAS,IACnF,MAAM,YACP;AACN,YAAM,OAAO,uBAAuB,QAAQ;AAC5C,UAAI,KAAM,QAAO,cAAc;AAAA,IACjC;AACA,UAAM,QAAQ,4BAA4B,KAAK;AAC/C,QAAI,OAAO;AACT;AAAA,QACE;AAAA,QACA,4BAA4B;AAAA,UAC1B,SAAS,MAAM;AAAA,UACf,UAAU,MAAM;AAAA,UAChB,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM;AAAA,UACd,mBAAmB,MAAM;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,MAAM,SAAS,UAAU;AAC3B,yBAAmB,QAAQ,KAAK;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAjJA;AAAA;AAAA;AACA;AAIA;AAAA;AAAA;;;ACwDA,SAASC,MAAK,WAAmB,MAAM,KAAa;AAClD,QAAMC,WAAU,UAAU,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACpD,SAAOA,SAAQ,SAAS,MAAM,GAAGA,SAAQ,MAAM,GAAG,MAAM,CAAC,CAAC,WAAMA;AAClE;AAOO,SAAS,oBACd,WAC2B;AAC3B,QAAM,QAAQ,aAAa,IAAI,KAAK;AACpC,MAAI,CAAC,KAAM,QAAO;AAClB,aAAW,WAAW,kBAAkB;AACtC,QAAI,QAAQ,KAAK,KAAK,IAAI,GAAG;AAC3B,aAAO,EAAE,SAAS,MAAM,QAAQ,GAAG,QAAQ,KAAK,KAAKD,MAAK,IAAI,CAAC,GAAG;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AACT;AAlFA,IA6BM;AA7BN;AAAA;AAAA;AA6BA,IAAM,mBAAqC;AAAA,MACzC;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;;;ACvCA,SAAS,WAAW,OAA+B;AACjD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,UAAU;AACpC;AAEA,SAAS,eAAe,OAAyB;AAC/C,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,EAAE,SAAS;AAC5D,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,SAAS;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,KAAe,EAAE,SAAS;AAC5E,SAAO;AACT;AAEA,SAAS,0BAA0B,UAAyD;AAC1F,MAAI,CAAC,UAAU,QAAS,QAAO;AAC/B,MAAI,SAAS,yBAAyB,MAAO,QAAO;AACpD,SAAO,WAAW,SAAS,IAAI;AACjC;AAEA,SAAS,qBACP,MACA,kBACA,YACQ;AACR,QAAM,QAAkB,CAAC,6BAA6B;AACtD,MAAI,SAAS,iBAAiB,SAAS,QAAQ;AAC7C,UAAM;AAAA,MACJ,GAAG,gBAAgB,sBAAsB,qBAAqB,IAAI,KAAK,GAAG;AAAA,IAC5E;AAAA,EACF;AACA,OAAK,SAAS,qBAAqB,SAAS,WAAW,YAAY;AACjE,UAAM,MAAM,WAAW,SAAS,KAAK,WAAW,MAAM,GAAG,EAAE,IAAI;AAC/D,UAAM,KAAK,UAAU,GAAG,qCAAqC;AAAA,EAC/D;AACA,QAAM,KAAK,qFAAgF;AAC3F,SAAO,MAAM,KAAK,IAAI;AACxB;AAMO,SAAS,0BAA0B,OAMP;AACjC,MAAI,MAAM,SAAS,eAAe,MAAM,WAAW,EAAG,QAAO;AAE7D,QAAM,oBAAoB,MAAM,gBAAgB,CAAC,GAAG,OAAO,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE;AAClF,QAAM,aAAa,WAAW,MAAM,UAAU,KAAK,0BAA0B,MAAM,WAAW;AAC9F,QAAM,iBAAiB,mBAAmB;AAC1C,QAAM,oBAAoB,QAAQ,UAAU;AAE5C,MAAI,CAAC,kBAAkB,CAAC,mBAAmB;AACzC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,YAAY;AAAA,MACZ,iBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,OACJ,kBAAkB,oBAAoB,SAAS,iBAAiB,gBAAgB;AAElF,SAAO;AAAA,IACL;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,iBAAiB,qBAAqB,MAAM,kBAAkB,UAAU;AAAA,EAC1E;AACF;AAjGA;AAAA;AAAA;AAAA;AAAA;;;ACsBA,SAASE,YAAW,OAA+B;AACjD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,UAAU;AACpC;AAEA,SAASC,gBAAe,OAAyB;AAC/C,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,EAAE,SAAS;AAC5D,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,SAAS;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,KAAe,EAAE,SAAS;AAC5E,SAAO;AACT;AAEA,SAAS,uBAAuB,UAA0C;AACxE,MAAID,YAAW,SAAS,UAAU,EAAG,QAAO;AAC5C,MAAIA,YAAW,SAAS,KAAK,EAAG,QAAO;AACvC,MAAIA,YAAW,SAAS,kBAAkB,EAAG,QAAO;AACpD,MAAIA,YAAW,SAAS,SAAS,EAAG,QAAO;AAC3C,QAAM,WAAW,SAAS;AAC1B,MAAI,UAAU,WAAW,SAAS,yBAAyB,SAASA,YAAW,SAAS,IAAI,GAAG;AAC7F,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAMO,SAAS,oBAAoB,UAAuD;AACzF,MAAI,CAACC,gBAAe,SAAS,WAAW,EAAG,QAAO,EAAE,SAAS,MAAM;AACnE,MAAI,SAAS,aAAa,WAAW,EAAG,QAAO,EAAE,SAAS,MAAM;AAChE,MAAI,CAAC,uBAAuB,QAAQ,GAAG;AACrC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ,gBAAgB,SAAS,aAAa,MAAM;AAAA,IACtD;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,gBAAgB,SAAS,aAAa,MAAM;AAAA,EACtD;AACF;AAEO,SAAS,uBAAuB,SAAmD;AACxF,MAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,SAAO,QAAQ,UAAU,QAAQ,UAAU;AAC7C;AAxEA;AAAA;AAAA;AAAA;AAAA;;;ACEA,SAASC,oBAAmB,MAA8C;AACxE,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAQ,WAAW,GAAG,EAAG,QAAO;AACrC,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,QAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,QAAyC;AACzE,QAAM,MACJ,OAAO,0BACP,OAAO,4BACP,OAAO,aACP,OAAO;AACT,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,SAAS;AAC3C;AAEO,SAAS,uCACd,OACgC;AAChC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,SAASA,oBAAmB,OAAO;AACzC,MAAI,OAAQ,QAAO;AAEnB,QAAM,aAAwC,CAAC;AAE/C,QAAM,UAAU;AAChB,MAAI;AACJ,UAAQ,aAAa,QAAQ,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,YAAYA,oBAAmB,WAAW,CAAC,KAAK,EAAE;AACxD,QAAI,UAAW,YAAW,KAAK,SAAS;AAAA,EAC1C;AAEA,QAAM,aAAa,QAAQ,QAAQ,GAAG;AACtC,QAAM,YAAY,QAAQ,YAAY,GAAG;AACzC,MAAI,cAAc,KAAK,YAAY,YAAY;AAC7C,UAAM,QAAQA,oBAAmB,QAAQ,MAAM,YAAY,YAAY,CAAC,CAAC;AACzE,QAAI,MAAO,YAAW,KAAK,KAAK;AAAA,EAClC;AAEA,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,MAAI,OAAO,WAAW,WAAW,SAAS,CAAC;AAC3C,MAAI,YAAY,yBAAyB,IAAI;AAC7C,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,yBAAyB,SAAS;AAChD,QAAI,QAAQ,WAAW;AACrB,aAAO;AACP,kBAAY;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AA9DA;AAAA;AAAA;AAAA;AAAA;;;ACmCA,SAASC,YAAW,OAA+B;AACjD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,IAAI,MAAM,KAAK;AACrB,SAAO,EAAE,SAAS,IAAI;AACxB;AAEA,SAASC,gBAAe,OAAyB;AAC/C,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,EAAE,SAAS;AAC5D,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,KAAe,EAAE,SAAS;AAC5E,SAAO;AACT;AAEA,SAAS,eAAe,KAA4B;AAClD,QAAM,IAAI,IACP,KAAK,EACL,MAAM,qDAAqD;AAC9D,MAAI,CAAC,EAAG,QAAOD,YAAW,GAAG;AAC7B,SAAO,sBAAsB,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;AAChD;AAEA,SAAS,YAAY,KAAqB;AACxC,QAAM,IAAI,IACP,KAAK,EACL,MAAM,qDAAqD;AAC9D,MAAI,CAAC,EAAG,QAAO,IAAI,KAAK,EAAE,YAAY;AACtC,SAAO,GAAG,EAAE,CAAC,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;AAC3C;AAEA,SAAS,oBAAoB,aAAgD;AAC3E,MAAI,SAAyC;AAC7C,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAM,WAAW,uCAAuC,WAAW;AACnE,QAAI,SAAU,UAAS;AAAA,EACzB,WAAW,eAAe,OAAO,gBAAgB,YAAY,CAAC,MAAM,QAAQ,WAAW,GAAG;AACxF,aAAS;AAAA,EACX;AACA,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,QAAM,MAAM,OAAO,0BAA0B,OAAO;AACpD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,QAAM,MAAgC,CAAC;AACvC,aAAW,QAAQ,KAAK;AACtB,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG;AAC9D,UAAM,MAAM;AACZ,UAAM,QAAQ,eAAe,OAAO,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;AAClE,UAAM,UAAUA,YAAW,IAAI,OAAO;AACtC,QAAI,CAAC,SAAU,YAAY,YAAY,YAAY,aAAa,YAAY,UAAY;AACxF,QAAI,KAAK;AAAA,MACP;AAAA,MACA;AAAA,MACA,aAAaA,YAAW,IAAI,eAAe,IAAI,YAAY;AAAA,MAC3D,QAAQA,YAAW,IAAI,MAAM;AAAA,IAC/B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGA,SAAS,qBAAqB,UAAiC,aAAgC;AAC7F,QAAM,OAAiB,CAAC;AACxB,QAAM,eAAe,eAAeA,YAAW,SAAS,KAAK,KAAK,EAAE;AACpE,MAAI,aAAc,MAAK,KAAK,YAAY;AACxC,MAAI,eAAe,OAAO,gBAAgB,YAAY,CAAC,MAAM,QAAQ,WAAW,GAAG;AACjF,UAAM,SAAS;AACf,UAAM,KAAK,eAAe,OAAO,OAAO,SAAS,OAAO,UAAU,EAAE,CAAC;AACrE,QAAI,GAAI,MAAK,KAAK,EAAE;AAAA,EACtB;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AAC1B;AAEO,SAAS,4BAA4B,OAIX;AAC/B,QAAM,EAAE,UAAU,SAAS,IAAI;AAC/B,QAAM,cAAc,MAAM,eAAe,SAAS;AAElD,MACE,CAAC,SAAS,eACV,SAAS,aAAa,WAAW,KACjC,CAAC,SAAS,yBACV;AACA,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B;AACA,MAAI,CAACC,gBAAe,WAAW,GAAG;AAChC,UAAM,gBACJ,SAAS,mCACR,SAAS,eACR,QAAQ,SAAS,uBAAuB,KACxC,SAAS,aAAa,SAAS;AACnC,QAAI,iBAAiB,SAAS,aAAa,SAAS,GAAG;AACrD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,QAAQ,oDAAoD,SAAS,aAAa,KAAK,IAAI,CAAC;AAAA,MAC9F;AAAA,IACF;AACA,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B;AAEA,QAAM,iCACJ,SAAS,mCACR,SAAS,eACR,QAAQ,SAAS,uBAAuB,KACxC,SAAS,aAAa,SAAS;AAEnC,MAAI,CAAC,kCAAkC,CAAC,SAAS,yBAAyB;AACxE,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B;AAEA,QAAM,eAAe,SAAS,0BAC1B,eAAeD,YAAW,SAAS,WAAW,KAAK,EAAE,MACpD,SAAS,aAAa,WAAW,IAC9B,eAAe,SAAS,aAAa,CAAC,CAAE,IACxC,QACJ;AACJ,MAAI,cAAc;AAChB,UAAM,YAAY,qBAAqB,UAAU,WAAW;AAC5D,UAAM,aACJ,eACA,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,KACzB,YAAwC,+BAA+B;AAC1E,QAAI,CAAC,YAAY;AACf,iBAAW,MAAM,WAAW;AAC1B,YAAI,OAAO,cAAc;AACvB,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ,uCAAuC,EAAE,gCAAgC,YAAY;AAAA,UAC/F;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,UAAME,kBAAiB,oBAAoB,WAAW;AACtD,UAAM,QAAQA,gBAAe,KAAK,CAAC,MAAM,EAAE,UAAU,YAAY;AACjE,QACE,CAAC,SACA,MAAM,YAAY,YACjB,EAAE,MAAM,QAAQ,KAAK,MAAM,MAAM,YAAY,aAAa,MAAM,YAAY,aAC9E;AACA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,QAAQ,0CAA0C,YAAY;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,oBAAoB,WAAW;AACtD,QAAM,QAAQ,IAAI;AAAA,IAChB,eAAe,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,GAAG,CAAC,CAAU;AAAA,EAC9D;AACA,QAAM,YAAY,IAAI;AAAA,IACpB,SAAS,aAAa,IAAI,CAAC,MAAM,YAAY,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,OAAO;AAAA,EACtF;AACA,QAAM,cAAc,qBAAqB,UAAU,WAAW;AAE9D,MAAI,SAAS,aAAa;AACxB,eAAW,MAAM,aAAa;AAC5B,UAAI,UAAU,OAAO,KAAK,CAAC,UAAU,IAAI,YAAY,EAAE,CAAC,GAAG;AACzD,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,6CAA6C,EAAE;AAAA,QACzD;AAAA,MACF;AACA,UAAI,UAAU,SAAS,GAAG;AACxB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,aAAa,WAAW,EAAG,QAAO,EAAE,SAAS,MAAM;AAEhE,QAAM,UAAoB,CAAC;AAC3B,aAAW,UAAU,SAAS,cAAc;AAC1C,UAAM,MAAM,YAAY,eAAe,MAAM,KAAK,MAAM;AACxD,UAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,QAAI,CAAC,OAAO;AACV,cAAQ,KAAK,GAAG;AAChB;AAAA,IACF;AACA,QAAI,MAAM,YAAY,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACvD,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,QAAQ,MAAM,CAAC,MAAM,MAAM,IAAI,CAAC,CAAC,IACrC,iCACA;AAAA,MACJ,QAAQ,wCAAwC,QAAQ,KAAK,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,MAAM;AAC1B;AAEO,SAAS,+BACd,SACoB;AACpB,MAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,SAAO,QAAQ,UAAU,QAAQ;AACnC;AAtPA;AAAA;AAAA;AAEA;AAAA;AAAA;;;AC8NO,SAAS,iBAAiB,OAqBb;AAClB,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,MAAM,qBAAqB,CAAC,mCAAmC,MAAM,iBAAiB,GAAG;AAC3F,WAAO,EAAE,OAAO,WAAW,QAAQ,MAAM,kBAAkB;AAAA,EAC7D;AACA,MAAI,MAAM,aAAa;AACrB,QAAI,MAAM,aAAa,gCAAgC,MAAM,WAAW,GAAG;AACzE,aAAO,EAAE,OAAO,QAAQ,QAAQ,4CAA4C;AAAA,IAC9E;AACA,UAAM,kBAAkB;AAAA,MACtB,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM,gBAAgB,CAAC;AAAA,MACrC,aAAa,MAAM,eAAe;AAAA,MAClC,OAAO,MAAM,SAAS;AAAA,IACxB;AACA,UAAM,UAAU,oBAAoB,eAAe;AACnD,QAAI,QAAQ,SAAS;AACnB,YAAM,SAAS,uBAAuB,OAAO;AAC7C,aAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ,QAAQ,SACZ,oBAAoB,QAAQ,MAAM,MAAM,MAAM,KAC9C,oBAAoB,MAAM;AAAA,MAChC;AAAA,IACF;AACA,QAAI,MAAM,iBAAiB;AACzB,YAAM,kBAAkB,4BAA4B;AAAA,QAClD,UAAU,MAAM;AAAA,QAChB,UAAU;AAAA,QACV,aAAa,MAAM;AAAA,MACrB,CAAC;AACD,YAAM,iBAAiB,+BAA+B,eAAe;AACrE,UAAI,gBAAgB;AAClB,eAAO;AAAA,UACL,OAAO;AAAA,UACP,QAAQ,gBAAgB,SACpB,qBAAqB,gBAAgB,MAAM,MAAM,cAAc,KAC/D,qBAAqB,cAAc;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,OAAO,QAAQ,QAAQ,wBAAwB;AAAA,EAC1D;AACA,MAAI,CAAC,MAAM,OAAO;AAChB,QAAI,uBAAuB,KAAK,GAAG;AACjC,aAAO,EAAE,OAAO,QAAQ,QAAQ,gCAAgC;AAAA,IAClE;AAIA,UAAM,aAAa,oBAAoB,MAAM,KAAK;AAClD,QAAI,WAAY,QAAO,EAAE,OAAO,WAAW,QAAQ,WAAW,OAAO;AACrE,UAAM,UAAU,0BAA0B;AAAA,MACxC,OAAO;AAAA,MACP,aAAa;AAAA,MACb,cAAc,MAAM;AAAA,MACpB,aAAa,MAAM;AAAA,IACrB,CAAC;AACD,QAAI,SAAS,aAAa;AACxB,YAAMC,QAAO,MAAM,OAAO,KAAK;AAC/B,aAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQA,QAAO,GAAG,QAAQ,eAAe,KAAKA,KAAI,MAAM,QAAQ;AAAA,MAClE;AAAA,IACF;AACA,UAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,OACJ,0CAA0C,IAAI,KAC9C,SAAS,mBAAmB;AAAA,IAClC;AAAA,EACF;AACA,MAAI,MAAM,kBAAkB;AAC1B,WAAO,EAAE,OAAO,WAAW,QAAQ,sCAAsC,MAAM,gBAAgB,GAAG;AAAA,EACpG;AACA,QAAM,UAAU,MAAM,YAAY,KAAK,MAAM,MAAM,SAAS,IAAI;AAChE,MACE,CAAC,MAAM,gBACP,MAAM,gBAAgB,KACtB,MAAM,mBAAmB,KACzB,OAAO,SAAS,OAAO,KACvB,MAAM,UAAU,aAChB;AACA,WAAO,EAAE,OAAO,mBAAmB,QAAQ,yBAAyB,QAAQ,OAAO,CAAC,gBAAgB;AAAA,EACtG;AACA,QAAM,QAAQ,MAAM,iBAAiB,KAAK,MAAM,MAAM,cAAc,IAAI;AACxE,MAAI,OAAO,SAAS,KAAK,KAAK,MAAM,QAAQ,UAAU;AACpD,WAAO,EAAE,OAAO,SAAS,QAAQ,uCAAuC,QAAQ,KAAK,CAAC,IAAI;AAAA,EAC5F;AACA,SAAO,EAAE,OAAO,MAAM,QAAQ,kBAAkB;AAClD;AAEA,SAAS,mCAAmC,QAA4C;AACtF,QAAM,OAAO,QAAQ,KAAK;AAC1B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,kDAAkD,KAAK,IAAI,KAAK,yBAAyB,KAAK,IAAI;AAC3G;AAEA,SAAS,uBAAuB,OAUpB;AACV,MAAI,MAAM,YAAa,QAAO;AAC9B,MAAI,MAAM,UAAU,MAAM,UAAW,QAAO;AAC5C,MAAI,MAAM,cAAc,MAAM,MAAM,eAAe,KAAK,KAAK,MAAM,iBAAiB,EAAG,QAAO;AAC9F,MAAI,MAAM,OAAO,KAAK,EAAG,QAAO;AAChC,OAAK,MAAM,gBAAgB,CAAC,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAG,QAAO;AACnE,SAAO,qCAAqC,KAAK,MAAM,mBAAmB,EAAE;AAC9E;AAEA,SAAS,gCAAgC,OAAyB;AAChE,MAAI,SAAyC;AAC7C,MAAI,OAAO,UAAU,SAAU,UAAS,uCAAuC,KAAK;AAAA,WAC3E,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,EAAG,UAAS;AAC/E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,MAAM,OAAO,0BAA0B,OAAO;AACpD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAChC,SAAO,IAAI,KAAK,CAAC,SAAyC;AACxD,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG,QAAO;AACrE,WAAO,OAAQ,KAAiC,WAAW,EAAE,EAAE,KAAK,MAAM;AAAA,EAC5E,CAAC;AACH;AAEA,SAAS,mBACP,QACA,mBACA,WACS;AACT,QAAM,cAAc,OAAO,oBAAoB;AAC/C,MAAI,OAAO,wBAAwB,+BAA+B,gBAAgB,UAAa,gBAAgB,MAAM;AACnH,WAAO;AAAA,EACT;AACA,MAAI,kBAAmB,QAAO;AAC9B,MAAI,gBAAgB,UAAa,gBAAgB,KAAM,QAAO;AAC9D,SAAO,iCAAiC,SAAS;AACnD;AAEO,SAAS,oBAAoB,QAA6B,UAA+B,CAAC,GAA2B;AAC1H,QAAM,SAAS,mBAAmB,OAAO,UAAU;AACnD,QAAM,YAAY,eAAe,OAAO,aAAa;AACrD,QAAM,yBACJ,OAAO,OAAO,yBAAyB,YAAY,OAAO,qBAAqB,KAAK,EAAE,SAAS;AACjG,QAAM,cAAc,mBAAmB,QAAQ,OAAO,aAAa,SAAS;AAC5E,QAAM,QAAQ,yBAAyB,QAAQ,WAAW,OAAO,GAAG;AACpE,QAAM,cAAc,SAAS,OAAO,UAAU;AAC9C,QAAM,cAAc,SAAS,OAAO,UAAU;AAC9C,QAAM,iBAAiB,SAAS,OAAO,aAAa;AACpD,QAAM,eAAe,eAAe,OAAO,YAAY;AACvD,QAAM,cAAc,mBAAmB,OAAO,cAAc;AAAA,IAC1D,MAAM,QAAQ;AAAA,IACd,YAAY,QAAQ;AAAA,EACtB,CAAC;AACD,QAAM,iBAAiB,UAAU;AAAA,IAC/B,OAAO;AAAA,IACP,UAAU;AAAA,IACV,UAAU,OAAO,UAAU;AAAA,IAC3B,UAAU,OAAO,UAAU;AAAA,IAC3B,UAAU,OAAO,aAAa;AAAA,EAChC,CAAC;AAID,QAAM,QACJ,OAAO,UACN,CAAC,SAAS,CAAC,cAAc,SAAS,OAAO,YAAY,EAAE,EAAE,KAAK,KAAK,SAAY;AAClF,QAAM,oBACJ,OAAO,OAAO,sBAAsB,YAAY,OAAO,kBAAkB,KAAK,IAC1E,OAAO,kBAAkB,KAAK,IAC9B;AACN,QAAM,6BAA6B,mCAAmC,iBAAiB,IACnF,OACA;AACJ,QAAM,kBAAgD,OAAO,oBACzD;AAAA,IACE,aAAa;AAAA,IACb,cAAc,CAAC,OAAO,iBAAiB;AAAA,IACvC,aAAa,OAAO;AAAA,IACpB,yBAAyB;AAAA,EAC3B,IACA;AAEJ,QAAM,YAAY,iBAAiB;AAAA,IACjC;AAAA,IACA;AAAA,IACA,cAAc,OAAO;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB,UAAU;AAAA,IAC5B,WAAW,OAAO;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB;AAAA,IACA,OAAO,OAAO,qBAAqB,OAAO,aAAa;AAAA,IACvD,WAAW,OAAO,cAAc;AAAA,IAChC,QAAQ,OAAO,UAAU;AAAA,IACzB,WAAW,OAAO,aAAa;AAAA,IAC/B,iBAAiB,OAAO,mBAAmB;AAAA,EAC7C,CAAC;AACD,QAAM,oBACJ,8BAA8B,UAAU,UAAU,YAC9C,YACA,0BAA0B,UAAU,UAAU,SAC5C,SACA,cACE,WACA,QACE,YACA;AACZ,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,IACf,KAAK,OAAO;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,cAAc,OAAO;AAAA,IACrB,YAAY,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,OAAO;AAAA,IACrB,aAAa,OAAO;AAAA,IACpB;AAAA,IACA,aAAa,yBAAyB,OAAO,OAAO;AAAA,IACpD,gBAAgB,UAAU;AAAA,IAC1B,iBAAiB,UAAU;AAAA,IAC3B,oBAAoB,UAAU;AAAA,IAC9B,sBAAsB,UAAU;AAAA,IAChC,kBAAkB,UAAU;AAAA,IAC5B,oBAAoB,UAAU;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,8BAA8B,OAAO,gCAAgC;AAAA,IACrE,2BAA2B,OAAO,6BAA6B;AAAA,IAC/D,OAAO,OAAO,SAAS,OAAO,oBAAoB,SAAS;AAAA,IAC3D,UAAU,OAAO,oBAAoB,YAAY;AAAA,IACjD,SAAS,OAAO,WAAW;AAAA,IAC3B,OAAO,OAAO,SAAS;AAAA,IACvB,WAAW,OAAO,aAAa;AAAA,IAC/B,aAAa,OAAO,eAAe;AAAA,IACnC,YAAY,OAAO,cAAc;AAAA,IACjC,WAAW,OAAO,aAAa;AAAA,EACjC;AACF;AAEO,SAAS,uBAAuB,QAAyC;AAC9E,MAAI,OAAO,YAAa,QAAO;AAC/B,MAAI,OAAO,UAAU,MAAO,QAAO;AACnC,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,OAAQ,QAAO;AACnE,SAAO;AACT;AAGO,SAAS,6BAA6B,QAAyC;AACpF,MAAI,CAAC,OAAO,YAAa,QAAO;AAChC,SAAO,OAAO,UAAU,UAAU,qBAAqB,OAAO,UAAU,UAAU;AACpF;AApgBA,IAsBa,aACA;AAvBb;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AASO,IAAM,cAAc;AACpB,IAAM,WAAW;AAAA;AAAA;;;ACvBxB;AAAA;AAAA;AAEA;AAAA;AAAA;;;ACFA,IAkBa,8BAGA;AArBb;AAAA;AAAA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAMO,IAAM,+BAA+B,MAAM,OAAO;AAGlD,IAAM,4BAA4B,IAAI,OAAO,OAAO;AAAA;AAAA;;;ACrB3D;AAAA;AAAA;AACA;AAAA;AAAA;;;ACDA,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,iBAAAC,sBAAqB;AACnE,SAAS,WAAAC,UAAS,gBAAgB;AAClC,OAAOC,WAAU;AAgDV,SAAS,iBAAmC;AACjD,MAAI,CAACL,YAAW,WAAW,EAAG,QAAO,CAAC;AACtC,MAAI;AACF,WAAO,KAAK,MAAME,cAAa,aAAa,MAAM,CAAC;AAAA,EACrD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAzDA,IAuCM,YACA,aACA,kBAoFA,4BACA;AA9HN;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AA+BA,IAAM,aAAaG,MAAK,KAAKD,SAAQ,GAAG,SAAS;AACjD,IAAM,cAAcC,MAAK,KAAK,YAAY,aAAa;AACvD,IAAM,mBAAmBA,MAAK,KAAK,YAAY,aAAa;AAoF5D,IAAM,6BAA6B,MAAM,OAAO;AAChD,IAAM,0BAA0B,IAAI,OAAO,OAAO;AAAA;AAAA;;;AC9HlD,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,OAAOC,WAAU;AAcV,SAAS,qBAAqB,MAAsB;AACzD,MAAI,WAAWA,MAAK,QAAQ,gBAAgB,KAAK,KAAK,CAAC,CAAC;AACxD,SAAO,yBAAyB,IAAIA,MAAK,SAAS,QAAQ,CAAC,GAAG;AAC5D,eAAWA,MAAK,QAAQ,QAAQ;AAAA,EAClC;AACA,SAAO;AACT;AAGO,SAAS,qBAA6B;AAC3C,QAAM,MAAM,QAAQ,IAAI,uBAAuB,QAAQ,IAAI;AAC3D,MAAI,IAAK,QAAO,qBAAqB,GAAG;AACxC,QAAM,aAAa,eAAe,EAAE,aAAa,KAAK;AACtD,MAAI,WAAY,QAAO,qBAAqB,UAAU;AACtD,QAAM,aAAaA,MAAK,KAAKD,SAAQ,GAAG,WAAW,SAAS;AAC5D,MAAID,YAAW,UAAU,EAAG,QAAO;AACnC,MAAIA,YAAW,WAAW,EAAG,QAAO;AACpC,SAAO;AACT;AAEO,SAAS,eAAe,aAA6B;AAC1D,SAAOE,MAAK,KAAK,qBAAqB,WAAW,GAAG,MAAM;AAC5D;AAEO,SAAS,oBAAoB,aAA6B;AAC/D,SAAOA,MAAK,KAAK,qBAAqB,WAAW,GAAG,WAAW;AACjE;AAEO,SAAS,kBAAkB;AAChC,QAAM,cAAc,mBAAmB;AACvC,SAAO;AAAA,IACL;AAAA,IACA,SAAS,eAAe,WAAW;AAAA,IACnC,cAAc,oBAAoB,WAAW;AAAA,EAC/C;AACF;AAEO,SAAS,OAAO,SAAiB,IAAoB;AAC1D,SAAOA,MAAK,KAAK,SAAS,SAAS,EAAE,CAAC;AACxC;AAvDA,IAOM,aAEA;AATN;AAAA;AAAA;AAGA;AACA;AACA;AAEA,IAAM,cAAcA,MAAK,KAAKD,SAAQ,GAAG,aAAa,SAAS;AAE/D,IAAM,2BAA2B,oBAAI,IAAI,CAAC,QAAQ,WAAW,CAAC;AAAA;AAAA;;;ACP9D;AAFA,OAAOE,YAAU;;;ACGjB;AAHA,OAAOC,WAAU;;;ACAjB;AACA;;;ACAO,IAAM,qCAAqC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,uBAAuB,UAA2B;AAChE,QAAM,aAAa,SAAS,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAClE,MAAI,eAAe,kBAAkB,WAAW,WAAW,eAAe,EAAG,QAAO;AACpF,aAAW,OAAO,oCAAoC;AACpD,QAAI,eAAe,OAAO,WAAW,WAAW,GAAG,GAAG,GAAG,EAAG,QAAO;AAAA,EACrE;AACA,SAAO;AACT;;;ACjBO,SAAS,wBAAwB,cAAkC;AACxE,SAAO,aAAa,OAAO,CAAC,SAAS;AACnC,UAAM,UAAU,KAAK,KAAK;AAC1B,UAAM,WAAW,QAAQ,WAAW,IAAI,IACpC,QAAQ,MAAM,CAAC,EAAE,KAAK,IACtB,QAAQ,SAAS,IACf,QAAQ,MAAM,CAAC,EAAE,KAAK,IACtB;AACN,WAAO,CAAC,uBAAuB,QAAQ;AAAA,EACzC,CAAC;AACH;;;ACTO,SAAS,qBAAqB,aAAqC;AACxE,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAM,QAAQ,YAAY,MAAM,2CAA2C;AAC3E,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB;AACA,MAAI,eAAe,OAAO,gBAAgB,UAAU;AAClD,UAAM,MAAM;AACZ,eAAW,OAAO,CAAC,SAAS,UAAU,gBAAgB,GAAG;AACvD,YAAM,QAAQ,IAAI,GAAG;AACrB,UAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAG,QAAO,MAAM,KAAK;AAAA,IACnE;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,mBAAmB,QAAyC;AAC1E,QAAM,WAAW,OAAO,aAAa;AACrC,MAAI,aAAa,YAAY,aAAa,UAAU;AAClD,WAAO,wBAAwB,OAAO,YAAY,EAAE,SAAS;AAAA,EAC/D;AACA,MAAI,qBAAqB,OAAO,WAAW,EAAG,QAAO;AACrD,MAAI,aAAa,WAAW,aAAa,WAAY,QAAO;AAC5D,MAAI,OAAO,aAAa,SAAS,KAAK,OAAO,YAAa,QAAO;AACjE,SAAO;AACT;;;AH5BA;AAGO,SAAS,sBAAsB,OAAgD;AACpF,MAAI,CAAC,MAAM,QAAQ;AACjB,UAAM,SAAS,oBAAoB,MAAM,QAAQ;AAAA,MAC/C,MAAM,MAAM,IAAI;AAAA,MAChB,YAAY,MAAM,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AACA,SAAO,MAAM;AACf;AAMO,SAAS,kCACd,OACA,gBACS;AACT,MAAI,MAAM,QAAQ;AAChB,WAAO,wBAAwB,MAAM,OAAO,YAAY,EAAE,SAAS;AAAA,EACrE;AACA,QAAM,YAAY,iBACd,eAAe,UAAU,MAAM,YAAY,IAC3C,eAAe,MAAM,YAAY;AACrC,SAAO,wBAAwB,SAAS,EAAE,SAAS;AACrD;AAEA,SAAS,0BAA0B,OAAiC;AAClE,QAAM,WAAW,MAAM,OAAO,oBAAoB;AAClD,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AACxD,MAAI,MAAM,OAAO,WAAW;AAC1B,WAAO,EAAE,OAAO,MAAM,OAAO,UAAU;AAAA,EACzC;AACA,SAAO;AACT;AAMO,SAAS,2BACd,OACA,KACwB;AACxB,MAAI,MAAM,OAAQ,QAAO,MAAM;AAE/B,QAAM,SAAS,MAAM;AACrB,QAAM,yBACJ,OAAO,OAAO,yBAAyB,YAAY,OAAO,qBAAqB,KAAK,EAAE,SAAS;AACjG,QAAM,qBACJ,QAAQ,OAAO,UAAU,CAAC,QAAQ,UAAU,WAAW,UAAU,WAAW,EAAE,SAAS,OAAO,MAAM,CAAC,KACrG;AACF,QAAM,cAAc,0BAA0B,KAAK;AAEnD,MAAI,sBAAsB,CAAC,WAAW,OAAO,GAAG,GAAG;AACjD,UAAM,eAAe,KAAK,iBACtB,IAAI,eAAe,UAAU,MAAM,YAAY,IAC/C,eAAe,MAAM,YAAY;AACrC,UAAM,YAAY,MAAM,IAAI,YAAY,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,KAAK;AAC5E,UAAM,QAAQ,KAAK,aAAa,iBAAiB,MAAM,cAAc,SAAS;AAC9E,UAAM,cACJ,UAAU,IACN;AAAA,MACE,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,IACA,mBAAmB,MAAM,cAAc;AAAA,MACrC,MAAM,MAAM,IAAI;AAAA,MAChB,YAAY,MAAM,IAAI;AAAA,IACxB,CAAC;AACP,UAAM,SAAS;AAAA,MACb,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,KAAK,OAAO;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ,OAAO,WAAW,yBAAyB,SAAS;AAAA,MAC5D,WAAW,EAAE,OAAO,yBAAyB,SAAS,QAAQ;AAAA,MAC9D,QAAQ,OAAO;AAAA,MACf,cAAc,MAAM;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,aAAa;AAAA,MACb,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,aAAa;AAAA,MACb,gBAAgB,OAAO,wBAAwB;AAAA,MAC/C,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,sBAAsB;AAAA,MACtB,kBAAkB;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBACE,OAAO,OAAO,sBAAsB,WAAW,OAAO,kBAAkB,KAAK,KAAK,OAAO;AAAA,MAC3F,OAAO,OAAO,qBAAqB,OAAO,aAAa,qBAAqB,WAAW;AAAA,IACzF;AACA,UAAM,SAAS;AACf,WAAO;AAAA,EACT;AAEA,SAAO,sBAAsB,KAAK;AACpC;;;ADxGA;;;AKVA;AACA;AACA;AACA;AAJA,OAAOC,WAAU;AAcV,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,wBAAwB,oBAAI,IAAI,CAAC,aAAa,UAAU,aAAa,MAAM,CAAC;AAMlF,SAAS,wBAAwB,KAAsC;AAC5E,QAAM,QAAQ,mBAAmB,GAAG;AACpC,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI,WAAW;AACf,MAAI,YAAY;AAChB,MAAI,uBAAuB;AAC3B,MAAI,oBAAoB;AACxB,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS;AAAA,MACbA,MAAK,KAAK,aAAa,IAAI,EAAE,GAAG,WAAW,SAAS,IAAI,GAAG,aAAa;AAAA,MACxE;AAAA,IACF;AACA,QAAI,CAAC,OAAQ;AACb,UAAM,SAAS,oBAAoB,QAAQ;AAAA,MACzC,MAAM,IAAI;AAAA,MACV,YAAY,IAAI;AAAA,IAClB,CAAC;AACD,QAAI,OAAO,SAAS,CAAC,OAAO,aAAa;AACvC,iBAAW;AACX;AAAA,IACF;AAMA,QAAI,OAAO,OAAO,sBAAsB,YAAY,OAAO,mBAAmB;AAC5E,6BAAuB;AAAA,IACzB;AACA,QAAI,6BAA6B,MAAM,GAAG;AACxC,0BAAoB;AAAA,IACtB;AACA,QAAI,OAAO,eAAe,OAAO,UAAU,UAAU,OAAQ,aAAY;AAAA,EAC3E;AACA,MAAI,SAAU,QAAO;AACrB,MAAI,qBAAsB,QAAO;AACjC,MAAI,kBAAmB,QAAO;AAC9B,SAAO,YAAY,cAAc;AACnC;AAYO,SAAS,oBAAyC;AACvD,QAAM,YAAiC,CAAC;AACxC,aAAW,OAAO,eAAe,GAAG;AAClC,QAAI,CAAC,oBAAoB,IAAI,IAAI,MAAM,EAAG;AAC1C,UAAM,OAAO,wBAAwB,GAAG;AACxC,QAAI,CAAC,QAAQ,SAAS,IAAI,OAAQ;AAClC,UAAM,OAAO,IAAI;AACjB,QAAI,SAAS;AACb,YAAQ,GAAG;AACX,cAAU,KAAK,EAAE,OAAO,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,EAClD;AACA,SAAO;AACT;;;ACzFA;;;ACDA;AAMA;AAUO,SAAS,uCACd,SACA,QACS;AACT,QAAM,UACJ,OAAO,QAAQ,OAAO,sBAAsB,WAAW,QAAQ,OAAO,kBAAkB,KAAK,IAAI;AACnG,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,oBAAoB,OAAO,EAAG,QAAO;AAEzC,QAAM,WAAW,UAAU,sBAAsB,OAAO;AACxD,MAAI,CAAC,uBAAuB,QAAQ,EAAG,QAAO;AAC9C,MAAI,mBAAmB,QAAQ,EAAG,QAAO;AACzC,MAAI,wBAAwB,SAAS,YAAY,EAAE,SAAS,EAAG,QAAO;AAEtE,QAAM,UAAU,oBAAoB;AAAA,IAClC,aAAa,SAAS;AAAA,IACtB,cAAc,SAAS;AAAA,IACvB,aAAa,SAAS;AAAA,IACtB,OAAO,qBAAqB,SAAS,WAAW;AAAA,EAClD,CAAC;AACD,MAAI,QAAQ,QAAS,QAAO;AAE5B,SAAO;AACT;;;AD/BA;AAEA,IAAM,gCAAgC,oBAAI,IAAI;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAQD,SAAS,kBACP,SACA,KACe;AACf,MAAI,IAAK,QAAO,IAAI,iBAAiB,OAAO,QAAQ,GAAG;AACvD,SAAO,wBAAwB,QAAQ,GAAG;AAC5C;AAMO,SAAS,oBAAoB,SAAmC;AACrE,MAAI,WAAW,QAAQ,OAAO,GAAG,EAAG,QAAO;AAC3C,MACE,OAAO,QAAQ,OAAO,yBAAyB,YAC/C,QAAQ,OAAO,qBAAqB,KAAK,EAAE,SAAS,GACpD;AACA,WAAO;AAAA,EACT;AACA,QAAM,eAAe,QAAQ,OAAO;AACpC,MAAI,gBAAgB,8BAA8B,IAAI,YAAY,EAAG,QAAO;AAC5E,MAAI,CAAC,QAAQ,OAAO,KAAK;AACvB,QAAI,iBAAiB,UAAW,QAAO;AACvC,WAAO,sBAAsB,OAAO,EAAE;AAAA,EACxC;AACA,SAAO;AACT;AAMO,SAAS,iBACd,SACA,KACS;AACT,MAAI,sBAAsB,IAAI,QAAQ,IAAI,MAAM,EAAG,QAAO;AAC1D,SAAO,kBAAkB,SAAS,GAAG,MAAM;AAC7C;AAMO,SAAS,yBACd,SACA,KACS;AACT,MAAI,oBAAoB,OAAO,EAAG,QAAO;AACzC,QAAM,eAAe,QAAQ,OAAO;AACpC,MACE,gBACA,8BAA8B,IAAI,YAAY,KAC9C,CAAC,QAAQ,OAAO,mBAChB;AACA,WAAO;AAAA,EACT;AACA,QAAM,SAAS,sBAAsB,OAAO;AAC5C,MAAI,uCAAuC,SAAS,MAAM,EAAG,QAAO;AAEpE,MAAI,uBAAuB,MAAM,EAAG,QAAO;AAC3C,MAAI,sBAAsB,IAAI,QAAQ,IAAI,MAAM,EAAG,QAAO;AAC1D,MAAI,iBAAiB,SAAS,GAAG,EAAG,QAAO;AAC3C,SAAO,kBAAkB,SAAS,GAAG,MAAM;AAC7C;;;AN5CA,SAAS,uBAAuB,OAAmC;AACjE,QAAM,EAAE,SAAS,gBAAgB,gBAAgB,uBAAuB,IAAI;AAC5E,MAAI,CAAC,QAAS,QAAO,iBAAiB,yBAAyB;AAC/D,MAAI,sBAAsB,IAAI,QAAQ,IAAI,MAAM,GAAG;AACjD,WAAO;AAAA,EACT;AACA,MAAI,MAAM,YAAY,iBAAiB,SAAS,MAAM,QAAQ,GAAG;AAC/D,WAAO;AAAA,EACT;AACA,MACE,MAAM,YACN,uBAAuB,2BAA2B,SAAS,MAAM,QAAQ,CAAC,KAC1E,CAAC,oBAAoB,OAAO,GAC5B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,OAAqD;AACvF,QAAM,EAAE,SAAS,gBAAgB,gBAAgB,OAAO,cAAc,qBAAqB,IACzF;AACF,MAAI,CAAC,SAAS;AACZ,QAAI,CAAC,eAAgB,QAAO;AAC5B,WAAO,gBAAgB;AAAA,EACzB;AAIA,QAAM,iBAAiB,uBAAuB,KAAK;AACnD,MAAI,kBAAkB,KAAK,CAAC,kBAAkB,kBAAkB,EAAG,QAAO;AAC1E,MAAI,iBAAiB,KAAK,QAAQ,eAAgB,QAAO;AACzD,MAAI,oBAAoB,OAAO,EAAG,QAAO;AACzC,MAAI,kCAAkC,SAAS,MAAM,UAAU,cAAc,GAAG;AAC9E,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,UAAU,aAAa,iBAAiB,MAAM,YAAY;AAC9E,MAAI,UAAU,QAAQ,UAAU,UAAa,QAAQ,EAAG,QAAO;AAC/D,QAAM,SAAS,2BAA2B,SAAS,MAAM,QAAQ;AACjE,MAAI,uCAAuC,SAAS,MAAM,EAAG,QAAO;AACpE,MAAI,yBAAyB,SAAS,MAAM,QAAQ,EAAG,QAAO;AAC9D,MAAI,CAAC,uBAAuB,MAAM,EAAG,QAAO;AAC5C,MAAI,mBAAmB,MAAM,EAAG,QAAO;AACvC,MAAI,wBAAwB,OAAO,YAAY,EAAE,SAAS,EAAG,QAAO;AACpE,QAAM,UAAU,oBAAoB;AAAA,IAClC,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,aAAa,OAAO;AAAA,IACpB,OAAO,qBAAqB,OAAO,WAAW;AAAA,EAChD,CAAC;AACD,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,wBAAwB,MAAM,cAAc;AAC9C,UAAM,UAAU,qBAAqB;AAAA,MACnC,cAAc,MAAM;AAAA,MACpB,SAAS,QAAQ,OAAO;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,QAAQ,SAAS;AAAA,IACnB,CAAC;AACD,QAAI,SAAS;AACX,aAAO,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,IAAI,QAAQ;AAAA,IACvF;AAAA,EACF;AACA,SAAO;AACT;AAqBO,SAAS,2BAA2B,OAA4D;AACrG,QAAM,EAAE,SAAS,kBAAkB,OAAO,cAAc,qBAAqB,aAAa,IACxF;AACF,MAAI,CAAC,gBAAgB,QAAQ,iBAAkB,QAAO;AACtD,MAAI,oBAAoB,IAAIC,MAAK,QAAQ,YAAY,CAAC,EAAG,QAAO;AAChE,MAAI,WAAW,oBAAoB,OAAO,EAAG,QAAO;AACpD,MAAI,WAAW,kCAAkC,SAAS,MAAM,cAAc,GAAG;AAC/E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,sBAAsB,OAA4D;AAChG,SAAO,2BAA2B,KAAK;AACzC;;;AQKO,IAAM,8BAA8B,IAAI,KAAK,KAAK;AAGlD,IAAM,2BAA2B,IAAI,KAAK,KAAK,KAAK;AAGpD,IAAM,oCAAoC;AAG1C,IAAM,iCAAiC,KAAK,KAAK;AAGjD,IAAM,gCAAgC;AAEtC,IAAM,kCAAkC;;;AChK/C,IAAM,oBAAoB,oBAAI,IAAuB;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,0BACd,SACA,OACqE;AACrE,QAAM,MAA2E,CAAC;AAClF,QAAM,OAAO,oBAAI,IAAY;AAE7B,QAAM,OAAO,CAACC,QAAc,QAA2B,WAAoB;AACzE,UAAM,MAAM,GAAGA,MAAI,KAAK,MAAM;AAC9B,QAAI,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,gCAAiC;AACpE,SAAK,IAAI,GAAG;AACZ,QAAI,KAAK,EAAE,MAAAA,QAAM,QAAQ,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG,CAAC;AAAA,EAC1D;AAEA,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,kBAAkB,IAAI,KAAK,MAAM,EAAG;AACzC,SAAK,KAAK,MAAM,KAAK,QAAQ,KAAK,MAAM;AAAA,EAC1C;AACA,aAAW,UAAU,SAAS;AAC5B,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,WAAY;AAC3C,QAAI,CAAC,kBAAkB,IAAI,OAAO,UAAU,EAAG;AAC/C,SAAK,OAAO,MAAM,OAAO,UAAU;AAAA,EACrC;AAEA,SAAO;AACT;;;ACnCA,SAAS,cAAAC,cAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;;;ACCjB;AACA;AAHA,SAAS,cAAAC,cAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;;;ACDjB,SAAS,cAAAC,aAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;;;ACAjB;AACA;AAKA;;;ADJA;AACA;AACA;;;AEJA;AACA;AAFA,OAAOC,WAAU;AAIjB,IAAM,cAAc,GAAGA,MAAK,GAAG,OAAOA,MAAK,GAAG,OAAOA,MAAK,GAAG;AA+CtD,SAAS,oBAAoB,WAMlC;AACA,SAAO;AAAA,IACL,gBAAgBC,MAAK,KAAK,WAAW,aAAa;AAAA,IAClD,YAAYA,MAAK,KAAK,WAAW,cAAc;AAAA,IAC/C,YAAYA,MAAK,KAAK,WAAW,YAAY;AAAA,IAC7C,eAAeA,MAAK,KAAK,WAAW,iBAAiB;AAAA,IACrD,gBAAgBA,MAAK,KAAK,WAAW,kBAAkB;AAAA,EACzD;AACF;;;AF1DA;AAGO,IAAM,gCAAgC,KAAK,KAAK;AAahD,SAAS,yBAAyB,YAAoB,aAA8B;AACzF,QAAM,WAAWC,OAAK,QAAQ,UAAU;AACxC,QAAM,UAAUA,OAAK,QAAQ,eAAe,WAAW,CAAC;AACxD,QAAM,MAAMA,OAAK,SAAS,SAAS,QAAQ;AAC3C,SAAO,QAAQ,QAAQ,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,OAAK,WAAW,GAAG;AACtE;AAEA,SAAS,cAAc,SAA2B;AAChD,MAAI,CAACC,YAAW,OAAO,EAAG,QAAO,CAAC;AAClC,MAAI;AACF,WAAOC,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,EAChD,OAAO,CAAC,UAAU,MAAM,YAAY,KAAK,MAAM,SAAS,MAAM,EAC9D,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EAC9B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,sBAAsBC,SAA0B;AACvD,QAAM,aAAaH,OAAK,KAAKG,SAAQ,SAAS;AAC9C,MAAI,CAACF,YAAW,UAAU,EAAG,QAAO,CAAC;AACrC,MAAI;AACF,WAAOC,aAAY,YAAY,EAAE,eAAe,KAAK,CAAC,EACnD,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EACrC,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EAC9B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,oBAAoB,QAAgB,KAAa,UAA2B;AACnF,MAAI,CAACD,YAAW,MAAM,EAAG,QAAO;AAChC,MAAI;AACF,UAAM,MAAM,MAAMG,UAAS,MAAM,EAAE;AACnC,WAAO,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,MAAM;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,mCACd,WACA,MAAM,KAAK,IAAI,GACf,WAAW,+BACF;AACT,MAAI,CAACH,YAAW,SAAS,EAAG,QAAO;AACnC,QAAM,YAAY,oBAAoB,SAAS;AAC/C,QAAM,SAAS;AAAA,IACb,UAAU;AAAA,IACV;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,aAAa,WAAW,OAAO,GAAG,EAAG,QAAO;AACnE,QAAM,YAAY,eAAe,UAAU,aAAa;AACxD,MAAI,UAAU,iBAAiB;AAC7B,UAAM,MAAM,MAAM,KAAK,MAAM,UAAU,eAAe;AACtD,QAAI,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,MAAM,SAAU,QAAO;AAAA,EACjE;AACA,MAAI,oBAAoB,UAAU,YAAY,KAAK,QAAQ,EAAG,QAAO;AACrE,MAAI,oBAAoB,UAAU,eAAe,KAAK,QAAQ,EAAG,QAAO;AACxE,SAAO;AACT;AAGO,SAAS,gCACdE,SACA,MAAM,KAAK,IAAI,GACf,WAAW,+BACF;AACT,aAAW,QAAQ,sBAAsBA,OAAM,GAAG;AAChD,QAAI,mCAAmCH,OAAK,KAAKG,SAAQ,WAAW,IAAI,GAAG,KAAK,QAAQ,GAAG;AACzF,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAwFO,SAAS,6BAA6B,aAAqB,MAAM,KAAK,IAAI,GAAgB;AAC/F,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,UAAU,eAAe,WAAW;AAC1C,aAAW,SAAS,cAAc,OAAO,GAAG;AAC1C,UAAME,UAASC,OAAK,KAAK,SAAS,KAAK;AACvC,QAAI,gCAAgCD,SAAQ,GAAG,GAAG;AAChD,WAAK,IAAI,GAAG,WAAW,KAAK,KAAK,EAAE;AAAA,IACrC;AAAA,EACF;AACA,SAAO;AACT;;;AD3LA;AASA,SAAS,+BAA+B,QAA6B,KAAsB;AACzF,QAAM,QAAQ,CAAC,OAAO,eAAe,OAAO,YAAY,OAAO,UAAU;AACzE,aAAW,UAAU,OAAO;AAC1B,QAAI,CAACE,aAAW,MAAM,EAAG;AACzB,QAAI;AACF,YAAM,MAAM,MAAMC,UAAS,MAAM,EAAE;AACnC,UAAI,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,MAAM,8BAA+B,QAAO;AAAA,IACtF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAASC,uBAAsB,QAA6B,KAAsB;AAChF,MAAI,WAAW,OAAO,GAAG,EAAG,QAAO;AACnC,MAAI,OAAO,WAAW,aAAa,+BAA+B,QAAQ,GAAG,EAAG,QAAO;AACvF,SAAO;AACT;AAGO,SAAS,4BACd,cACA,MAAM,KAAK,IAAI,GACc;AAC7B,QAAM,sBAAsB,oBAAI,IAAY;AAC5C,QAAM,cAAc,oBAAI,IAAY;AAEpC,aAAW,eAAe,cAAc;AACtC,eAAW,OAAO,6BAA6B,WAAW,GAAG;AAC3D,UAAI,aAAa;AACjB,iBAAW,QAAQ,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC,GAAG;AACjD,cAAM,SAAS;AAAA,UACbC,OAAK,KAAK,eAAe,aAAa,IAAI,EAAE,GAAG,WAAW,SAAS,IAAI,GAAG,aAAa;AAAA,UACvF;AAAA,QACF;AACA,YAAI,CAAC,QAAQ,aAAc;AAC3B,cAAM,eAAeA,OAAK,QAAQ,OAAO,YAAY;AACrD,YAAI,CAACD,uBAAsB,QAAQ,GAAG,EAAG;AACzC,qBAAa;AACb,4BAAoB,IAAI,YAAY;AAAA,MACtC;AACA,UAAI,WAAY,aAAY,IAAI,GAAG,WAAW,KAAK,IAAI,EAAE,EAAE;AAAA,IAC7D;AACA,eAAW,OAAO,6BAA6B,WAAW,GAAG;AAC3D,kBAAY,IAAI,GAAG;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,EAAE,qBAAqB,YAAY;AAC5C;AAGO,SAAS,oBACd,cACA,aACA,OACA,aACS;AACT,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,YAAY,IAAI,GAAG,WAAW,KAAK,KAAK,EAAE;AACnD;;;AD1EA;AAYA,SAAS,UAAU,QAAgB,KAAqB;AACtD,MAAI;AACF,UAAM,QAAQE,UAAS,MAAM,EAAE;AAC/B,WAAO,KAAK,IAAI,GAAG,MAAM,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,aAAqB,OAAwC;AAClF,QAAM,UAAUC,OAAK,KAAK,aAAa,QAAQ,OAAO,UAAU;AAChE,MAAI,CAACC,aAAW,OAAO,EAAG,QAAO;AACjC,SAAO,SAAkC,SAAS,IAAI;AACxD;AAEA,SAAS,oBAAoB,SAA0B;AACrD,MAAI;AACF,UAAM,UAAUC,aAAY,OAAO;AACnC,WAAO,QAAQ,WAAW;AAAA,EAC5B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,wBAAwB,OAOX;AAC3B,QAAM,EAAE,aAAa,OAAO,SAAS,OAAO,qBAAqB,aAAa,IAAI;AAClF,MAAI,oBAAoB,SAAS,aAAa,OAAO,aAAa,WAAW,GAAG;AAC9E,WAAO;AAAA,EACT;AACA,MAAI,CAAC,oBAAoB,OAAO,EAAG,QAAO;AAC1C,QAAM,MAAM,cAAc,aAAa,KAAK;AAC5C,MAAI,OAAO,CAAC,sBAAsB,IAAI,IAAI,MAAM,GAAG;AACjD,QAAI,CAAC,wBAAwB,GAAG,EAAG,QAAO;AAAA,EAC5C;AACA,MAAI,sBAAsB,KAAK,QAAQ,oBAAqB,QAAO;AACnE,SAAO;AACT;AAGO,SAAS,gCACd,MACoB;AACpB,MAAI,CAACD,aAAW,KAAK,YAAY,EAAG,QAAO,CAAC;AAC5C,QAAM,aAAiC,CAAC;AACxC,MAAI;AACJ,MAAI;AACF,cAAUC,aAAY,KAAK,cAAc,EAAE,eAAe,KAAK,CAAC;AAAA,EAClE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,aAAW,YAAY,SAAS;AAC9B,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,UAAM,QAAQ,SAAS;AACvB,QAAI,KAAK,eAAe,UAAU,KAAK,YAAa;AACpD,UAAM,UAAUF,OAAK,KAAK,KAAK,cAAc,KAAK;AAClD,QAAI,CAAC,oBAAoB,OAAO,EAAG;AACnC,eAAW,KAAK;AAAA,MACd,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa,KAAK;AAAA,MAClB;AAAA,MACA,OAAO,UAAU,SAAS,KAAK,GAAG;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AK5FA;AADA,SAAS,cAAAG,cAAY,UAAAC,eAAc;;;ACAnC,SAAS,oBAAoB;AAC7B,SAAS,cAAAC,cAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;AAEjB,IAAM,wBAAwB;AAE9B,SAAS,qBAAqB,MAAc,YAAY,uBAAsC;AAC5F,MAAI,CAACH,aAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,MAAM,aAAa,MAAM,CAAC,OAAO,IAAI,GAAG;AAAA,MAC5C,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC,CAAC;AACD,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,KAAK,EAAE,CAAC;AACvC,UAAM,QAAQ,OAAO,KAAK;AAC1B,WAAO,OAAO,SAAS,KAAK,KAAK,SAAS,IAAI,QAAQ;AAAA,EACxD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,mBAAmB,MAAc,aAAa,KAAuB;AACnF,MAAI,CAACA,aAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,UAAU,qBAAqB,IAAI;AACzC,MAAI,YAAY,KAAM,QAAO;AAC7B,MAAI,QAAQ;AACZ,MAAI,OAAO;AACX,QAAM,QAAkB,CAAC,IAAI;AAC7B,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI;AACJ,QAAI;AACF,gBAAUC,aAAY,OAAO;AAAA,IAC/B,QAAQ;AACN;AAAA,IACF;AACA,eAAW,QAAQ,SAAS;AAC1B,UAAI,SAAS,WAAY,QAAO;AAChC,YAAM,OAAOE,OAAK,KAAK,SAAS,IAAI;AACpC,UAAI;AACJ,UAAI;AACF,aAAKD,UAAS,IAAI;AAAA,MACpB,QAAQ;AACN;AAAA,MACF;AACA,UAAI,GAAG,YAAY,EAAG,OAAM,KAAK,IAAI;AAAA,UAChC,UAAS,GAAG;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;;;ACvDA,SAAS,cAAAE,cAAY,cAAc;AAGnC;;;ACHA,SAAS,WAAW,eAAAC,oBAAmB;AAShC,SAAS,kBAAkB,YAA8C;AAC9E,MAAI;AACF,UAAM,KAAK,UAAU,UAAU;AAC/B,UAAM,eAAe,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI;AAC/E,UAAM,eAAe,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI;AAC/E,UAAM,UACJ,iBAAiB,SAChB,GAAG,QAAQ,gBAAiB,iBAAiB,QAAQ,GAAG,QAAQ;AACnE,WAAO,EAAE,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,QAAQ;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,yBAAyB,YAAoB,aAAa,IAAa;AACrF,QAAM,OAAO,kBAAkB,UAAU;AACzC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,QAAS,QAAO;AACzB,MAAI;AACF,UAAM,QAAQA,aAAY,UAAU;AACpC,QAAI,UAAU;AACd,eAAW,QAAQ,OAAO;AACxB,UAAI,WAAW,WAAY;AAC3B,YAAM,QAAQ,GAAG,WAAW,QAAQ,OAAO,EAAE,CAAC,IAAI,IAAI;AACtD,YAAM,OAAO,kBAAkB,KAAK;AACpC,iBAAW;AACX,UAAI,MAAM,QAAS,QAAO;AAAA,IAC5B;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;;;AC1CA,SAAS,aAAAC,kBAAiB;AAC1B,OAAOC,YAAU;;;ACDjB,OAAOC,YAAU;AAGjB,SAAS,6BACP,YACA,aACA,cACA,cAC0B;AAC1B,QAAM,WAAWA,OAAK,QAAQ,UAAU;AACxC,QAAM,SAAS,GAAGA,OAAK,GAAG,GAAG,YAAY;AACzC,QAAM,YAAY,SAAS,SAAS,MAAM,IAAI,WAAW;AACzD,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,MAAMA,OAAK,SAAS,cAAc,SAAS;AACjD,MAAI,IAAI,WAAW,IAAI,KAAKA,OAAK,WAAW,GAAG,EAAG,QAAO;AACzD,QAAM,QAAQ,IAAI,MAAMA,OAAK,GAAG;AAChC,MAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,MAAM,aAAc,QAAO;AACzE,MAAI,CAAC,SAAS,WAAWA,OAAK,QAAQ,WAAW,CAAC,EAAG,QAAO;AAC5D,SAAO;AACT;AAEO,SAAS,yBACd,YACA,aACA,cAC0B;AAC1B,SAAO,6BAA6B,YAAY,aAAa,cAAc,cAAc;AAC3F;AAEO,SAAS,uBACd,YACA,aACA,cAC0B;AAC1B,SAAO,6BAA6B,YAAY,aAAa,cAAc,OAAO;AACpF;AAEO,SAAS,wBACd,YACA,aACA,cAC0B;AAC1B,QAAM,WAAWA,OAAK,QAAQ,UAAU;AACxC,QAAM,UAAUA,OAAK,SAAS,cAAc,QAAQ;AACpD,MAAI,QAAQ,WAAW,IAAI,KAAKA,OAAK,WAAW,OAAO,EAAG,QAAO;AACjE,QAAM,QAAQ,QAAQ,MAAMA,OAAK,GAAG;AACpC,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,MAAI,CAAC,SAAS,WAAWA,OAAK,QAAQ,WAAW,CAAC,EAAG,QAAO;AAC5D,SAAO;AACT;AAEO,SAAS,4BACd,YACA,aACA,cACS;AACT,QAAM,WAAWA,OAAK,QAAQ,UAAU;AACxC,SACE,yBAAyB,UAAU,aAAa,YAAY,MAAM,QAClE,uBAAuB,UAAU,aAAa,YAAY,MAAM,QAChE,wBAAwB,UAAU,aAAa,YAAY,MAAM;AAErE;;;ADxDO,SAAS,+BAAsD;AACpE,QAAM,OAAO,QAAQ,IAAI,6BAA6B,QAAQ,KAAK,EAAE,YAAY;AACjF,MAAI,QAAQ,OAAO,QAAQ,WAAW,QAAQ,SAAS,QAAQ,KAAM,QAAO;AAC5E,MAAI,QAAQ,OAAO,QAAQ,UAAU,QAAQ,WAAW,QAAQ,MAAO,QAAO;AAC9E,SAAO;AACT;AAEA,SAAS,sBAAsB,MAAiD;AAC9E,QAAM,MAAMC,WAAU,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG;AAAA,IAC7C,UAAU;AAAA,IACV,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,EAClC,CAAC;AACD,SAAO;AAAA,IACL,IAAI,IAAI,WAAW;AAAA,IACnB,QAAQ,GAAG,IAAI,UAAU,EAAE,GAAG,IAAI,UAAU,EAAE,GAAG,KAAK;AAAA,EACxD;AACF;AAYO,SAAS,iCACd,YACA,aACA,cACyB;AACzB,MAAI,CAAC,4BAA4B,YAAY,aAAa,YAAY,GAAG;AACvE,WAAO,EAAE,IAAI,OAAO,OAAO,iDAAiD;AAAA,EAC9E;AACA,QAAM,eAAe,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI;AAC/E,QAAM,eAAe,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI;AAC/E,MAAI,iBAAiB,QAAQ,iBAAiB,MAAM;AAClD,WAAO,EAAE,IAAI,OAAO,OAAO,4CAA4C;AAAA,EACzE;AAEA,QAAM,QAAQ,sBAAsB;AAAA,IAClC;AAAA,IACA;AAAA,IACA,GAAG,YAAY,IAAI,YAAY;AAAA,IAC/BC,OAAK,QAAQ,UAAU;AAAA,EACzB,CAAC;AACD,MAAI,MAAM,IAAI;AACZ,WAAO,EAAE,IAAI,MAAM,QAAQ,gBAAgB;AAAA,EAC7C;AAEA,QAAM,KAAK,sBAAsB,CAAC,MAAM,OAAOA,OAAK,QAAQ,UAAU,CAAC,CAAC;AACxE,MAAI,GAAG,IAAI;AACT,WAAO,EAAE,IAAI,MAAM,QAAQ,UAAU;AAAA,EACvC;AAEA,QAAM,SAAS,MAAM,UAAU,GAAG,UAAU;AAC5C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,EACT;AACF;AAEO,IAAM,mCACX;;;AF9CF,SAAS,kBAAkB,OAAyB;AAClD,QAAM,OAAQ,OAA6C;AAC3D,SAAO,SAAS,YAAY,SAAS;AACvC;AAEO,SAAS,2BACd,WACA,SACA,OAAuC,CAAC,GACd;AAC1B,MAAI,CAACC,aAAW,UAAU,IAAI,GAAG;AAC/B,WAAO,EAAE,UAAU,OAAO,SAAS,MAAM,YAAY,mBAAmB;AAAA,EAC1E;AACA,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,UAAU,OAAO,SAAS,MAAM,YAAY,UAAU;AAAA,EACjE;AAEA,QAAM,cAAc,UAAU;AAC9B,QAAM,eAAe,cAAc,oBAAoB,WAAW,IAAI;AACtE,QAAM,cAAc,UAAU,SAAS,mBAAmB,UAAU,IAAI;AACxE,QAAM,gBAAgB,eAAe;AACrC,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,uBAAuB,KAAK,wBAAwB;AAE1D,MAAI;AACF,eAAW,UAAU,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC3D,WAAO,EAAE,UAAU,MAAM,SAAS,OAAO,OAAO,cAAc;AAAA,EAChE,SAAS,OAAO;AACd,QAAI,CAAC,kBAAkB,KAAK,KAAK,CAAC,eAAe,CAAC,cAAc;AAC9D,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,OAAQ,MAAgB;AAAA,MAC1B;AAAA,IACF;AAEA,UAAM,UAAU,qBAAqB,UAAU,IAAI;AACnD,UAAM,OAAO,6BAA6B;AAC1C,UAAM,sBAAsB,SAAS,WAAY,SAAS,UAAU;AACpE,QAAI,CAAC,qBAAqB;AACxB,aAAO,UACH;AAAA,QACE,UAAU;AAAA,QACV,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,OAAO,GAAI,MAAgB,OAAO,KAAK,gCAAgC;AAAA,MACzE,IACA;AAAA,QACE,UAAU;AAAA,QACV,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,OAAQ,MAAgB;AAAA,MAC1B;AAAA,IACN;AAEA,UAAM,UAAU,iCAAiC,UAAU,MAAM,aAAa,YAAY;AAC1F,QAAI,QAAQ,MAAM,QAAQ,WAAW,WAAW;AAC9C,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,IACF;AAEA,QAAI,QAAQ,IAAI;AACd,UAAI;AACF,mBAAW,UAAU,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC3D,eAAO;AAAA,UACL,UAAU;AAAA,UACV,SAAS;AAAA,UACT,OAAO;AAAA,UACP,mBAAmB;AAAA,QACrB;AAAA,MACF,SAAS,YAAY;AACnB,eAAO;AAAA,UACL,UAAU;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,OAAO,GAAI,WAAqB,OAAO;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,OAAO,GAAI,MAAgB,OAAO,gCAAgC,QAAQ,KAAK,KAAK,gCAAgC;AAAA,IACtH;AAAA,EACF;AACF;;;AFvGA,SAAS,uBAAuB,WAAmD;AACjF,QAAM,cAAc,UAAU;AAC9B,MAAI,CAAC,eAAe,CAAC,yBAAyB,UAAU,MAAM,WAAW,EAAG,QAAO;AACnF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AACF;AAEA,SAAS,sBAAsB,WAA6B,SAAiC;AAC3F,QAAM,eAAe,uBAAuB,SAAS;AACrD,MAAI,aAAc,QAAO;AACzB,QAAM,UAAU,2BAA2B,WAAW,OAAO;AAC7D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,QAAQ,SAAS,UAAU;AAAA,IAClC,UAAU,QAAQ;AAAA,IAClB,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,IACpB,OAAO,QAAQ;AAAA,EACjB;AACF;AAEO,SAAS,kBAAkB,WAA6B,SAAiC;AAC9F,SAAO,sBAAsB,WAAW,OAAO;AACjD;AAEO,SAAS,gBAAgB,WAA6B,SAAiC;AAC5F,SAAO,sBAAsB,WAAW,OAAO;AACjD;AAEO,SAAS,iBAAiB,WAA6B,SAAiC;AAC7F,SAAO,sBAAsB,WAAW,OAAO;AACjD;AAEO,SAAS,mBAAmB,WAA6B,SAAiC;AAC/F,QAAM,eAAe,uBAAuB,SAAS;AACrD,MAAI,aAAc,QAAO;AACzB,MAAI,CAACC,aAAW,UAAU,IAAI,GAAG;AAC/B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,UAAU;AAAA,EAC/E;AACA,MAAI;AACF,UAAM,cAAc,UAAU,SAAS,mBAAmB,UAAU,IAAI;AACxE,IAAAC,QAAO,UAAU,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACvD,WAAO;AAAA,MACL,GAAG;AAAA,MACH,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,OAAQ,MAAgB;AAAA,IAC1B;AAAA,EACF;AACF;AAEO,SAAS,eAAe,WAA6B,SAAiC;AAC3F,QAAM,eAAe,uBAAuB,SAAS;AACrD,MAAI,aAAc,QAAO;AACzB,MAAI,CAACD,aAAW,UAAU,IAAI,GAAG;AAC/B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,UAAU;AAAA,EAC/E;AACA,QAAM,OAAO,UAAU;AACvB,MAAI;AACF,UAAM,cAAc,UAAU,SAAS,mBAAmB,UAAU,IAAI;AACxE,QAAI,MAAM;AACR,UAAI,MAAM,CAAC,YAAY,UAAU,WAAW,UAAU,IAAI,GAAG,EAAE,cAAc,KAAK,CAAC;AAAA,IACrF;AACA,QAAIA,aAAW,UAAU,IAAI,GAAG;AAC9B,MAAAC,QAAO,UAAU,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACzD;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,OAAQ,MAAgB;AAAA,IAC1B;AAAA,EACF;AACF;;;AM3HA,SAAS,cAAAC,cAAY,eAAAC,cAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;AAgBjB,SAASC,WAAU,QAAgB,KAAqB;AACtD,MAAI;AACF,UAAM,QAAQC,UAAS,MAAM,EAAE;AAC/B,WAAO,KAAK,IAAI,GAAG,MAAM,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAa,OAAe,QAAyB;AAC5D,QAAM,MAAMC,OAAK,SAAS,QAAQ,KAAK;AACvC,SAAO,QAAQ,MAAO,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,OAAK,WAAW,GAAG;AACrE;AAoDA,SAAS,6BACP,cACA,MACA,MACA,MACoB;AACpB,QAAM,MAA0B,CAAC;AACjC,aAAW,OAAO,oCAAoC;AACpD,QAAI,QAAQ,QAAS;AACrB,UAAM,SAASC,OAAK,KAAK,cAAc,GAAG;AAC1C,QAAI,CAACC,aAAW,MAAM,EAAG;AACzB,UAAM,WAAWD,OAAK,QAAQ,MAAM;AACpC,QAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,QAAI,CAAC,aAAa,UAAU,KAAK,WAAW,EAAG;AAC/C,SAAK,IAAI,QAAQ;AACjB,QAAI,KAAK;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,OAAOE,WAAU,UAAU,KAAK,GAAG;AAAA,IACrC,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,MAA8C;AACrF,QAAM,aAAiC,CAAC;AACxC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,QAAI,KAAK,eAAe,MAAM,UAAU,KAAK,YAAa;AAC1D,eAAW;AAAA,MACT,GAAG,6BAA6B,MAAM,cAAc,MAAM,MAAM;AAAA,QAC9D,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,MAAM,MAAM,IAAI;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,kBAAkB,CAACD,aAAW,KAAK,YAAY,EAAG,QAAO;AAEnE,aAAW,YAAYE,aAAY,KAAK,cAAc,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9E,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,UAAM,UAAUH,OAAK,KAAK,KAAK,cAAc,SAAS,IAAI;AAC1D,eAAW,eAAeG,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACvE,UAAI,CAAC,YAAY,YAAY,EAAG;AAChC,YAAM,eAAeH,OAAK,KAAK,SAAS,YAAY,IAAI;AACxD,iBAAW;AAAA,QACT,GAAG,6BAA6B,cAAc,MAAM,MAAM;AAAA,UACxD,OAAO,SAAS;AAAA,UAChB,QAAQ,YAAY;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,uBAAuB,MAA8C;AAMnF,QAAM,iBAAiB,KAAK,iBAAiB,KAAK,KAAK;AACvD,QAAM,gBAAgB,KAAK;AAC3B,MAAI,CAAC,kBAAkB,CAAC,cAAe,QAAO,CAAC;AAE/C,QAAM,aAAiC,CAAC;AACxC,QAAM,OAAO,oBAAI,IAAY;AAE7B,MAAI,gBAAgB;AAClB,eAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,UAAI,KAAK,eAAe,MAAM,UAAU,KAAK,YAAa;AAC1D,YAAM,WAAW,MAAM;AACvB,UAAI,CAACC,aAAW,QAAQ,EAAG;AAC3B,UAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,WAAK,IAAI,QAAQ;AACjB,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,MAAM,MAAM,IAAI;AAAA,QAChB,OAAOC,WAAU,UAAU,KAAK,GAAG;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,CAAC,iBAAiB,CAACD,aAAW,KAAK,YAAY,EAAG,QAAO;AAG7D,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,iBAAa,IAAID,OAAK,QAAQ,MAAM,YAAY,CAAC;AAAA,EACnD;AAEA,aAAW,YAAYG,aAAY,KAAK,cAAc,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9E,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,QAAI,KAAK,eAAe,SAAS,SAAS,KAAK,YAAa;AAC5D,UAAM,UAAUH,OAAK,KAAK,KAAK,cAAc,SAAS,IAAI;AAC1D,QAAI;AACJ,QAAI;AACF,sBAAgBG,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC;AAAA,IAC9D,QAAQ;AACN;AAAA,IACF;AACA,eAAW,eAAe,eAAe;AACvC,UAAI,CAAC,YAAY,YAAY,EAAG;AAChC,YAAM,eAAeH,OAAK,QAAQA,OAAK,KAAK,SAAS,YAAY,IAAI,CAAC;AACtE,UAAI,KAAK,IAAI,YAAY,EAAG;AAC5B,UAAI,aAAa,IAAI,YAAY,EAAG;AACpC,UAAI,CAAC,aAAa,cAAc,KAAK,WAAW,EAAG;AACnD,WAAK,IAAI,YAAY;AACrB,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,SAAS;AAAA,QAChB,QAAQ,YAAY;AAAA,QACpB,OAAOE,WAAU,cAAc,KAAK,GAAG;AAAA,MACzC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACrNA,SAAS,cAAAE,cAAY,eAAAC,eAAa,YAAAC,iBAAgB;AAClD,OAAOC,YAAU;AAIjB,IAAM,wBAA6E;AAAA,EACjF,EAAE,SAAS,gBAAgB,MAAM,sBAAsB;AAAA,EACvD,EAAE,SAAS,SAAS,MAAM,oBAAoB;AAChD;AAYA,SAASC,WAAU,QAAgB,KAAqB;AACtD,MAAI;AACF,UAAM,QAAQF,UAAS,MAAM,EAAE;AAC/B,WAAO,KAAK,IAAI,GAAG,MAAM,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAASG,cAAa,OAAe,QAAyB;AAC5D,QAAM,MAAMF,OAAK,SAAS,QAAQ,KAAK;AACvC,SAAO,QAAQ,MAAO,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,OAAK,WAAW,GAAG;AACrE;AAEA,SAAS,cACP,YACA,MACA,MACA,YACA,MACA,MACM;AACN,MAAI,CAACH,aAAW,UAAU,EAAG;AAC7B,QAAM,WAAWG,OAAK,QAAQ,UAAU;AACxC,MAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,MAAI,CAACE,cAAa,UAAU,KAAK,WAAW,EAAG;AAC/C,OAAK,IAAI,QAAQ;AACjB,aAAW,KAAK;AAAA,IACd;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa,KAAK;AAAA,IAClB,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,OAAOD,WAAU,UAAU,KAAK,GAAG;AAAA,EACrC,CAAC;AACH;AAEA,SAAS,6BACP,YACA,MACA,MACA,cACA,MACM;AACN,aAAW,SAAS,uBAAuB;AACzC,kBAAc,YAAY,MAAM,MAAMD,OAAK,KAAK,cAAc,MAAM,OAAO,GAAG,MAAM,MAAM,IAAI;AAAA,EAChG;AACF;AAGO,SAAS,8BAA8B,MAAsD;AAClG,QAAM,aAAiC,CAAC;AACxC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,QAAI,KAAK,eAAe,MAAM,UAAU,KAAK,YAAa;AAC1D,iCAA6B,YAAY,MAAM,MAAM,MAAM,cAAc;AAAA,MACvE,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM,IAAI;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,KAAK,kBAAkB,CAACH,aAAW,KAAK,YAAY,EAAG,QAAO;AAEnE,aAAW,YAAYC,cAAY,KAAK,cAAc,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9E,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,QAAI,KAAK,eAAe,SAAS,SAAS,KAAK,YAAa;AAC5D,UAAM,UAAUE,OAAK,KAAK,KAAK,cAAc,SAAS,IAAI;AAC1D,QAAI;AACJ,QAAI;AACF,sBAAgBF,cAAY,SAAS,EAAE,eAAe,KAAK,CAAC;AAAA,IAC9D,QAAQ;AACN;AAAA,IACF;AACA,eAAW,eAAe,eAAe;AACvC,UAAI,CAAC,YAAY,YAAY,EAAG;AAChC,YAAM,eAAeE,OAAK,KAAK,SAAS,YAAY,IAAI;AACxD,mCAA6B,YAAY,MAAM,MAAM,cAAc;AAAA,QACjE,OAAO,SAAS;AAAA,QAChB,QAAQ,YAAY;AAAA,MACtB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACzGA;AAHA,SAAS,cAAAG,cAAY,YAAAC,iBAAgB;AACrC,OAAOC,YAAU;AAKjB,SAASC,WAAU,QAAgB,KAAqB;AACtD,MAAI;AACF,UAAM,QAAQF,UAAS,MAAM,EAAE;AAC/B,WAAO,KAAK,IAAI,GAAG,MAAM,KAAK;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,SAAS,uBAAuB,QAAqC;AACnE,QAAM,UAA+B,CAAC;AACtC,MAAI,UAAoC;AACxC,aAAW,QAAQ,OAAO,MAAM,IAAI,GAAG;AACrC,QAAI,CAAC,KAAK,KAAK,EAAG;AAClB,UAAM,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,MAAM,GAAG;AACrC,UAAM,QAAQ,KAAK,KAAK,GAAG;AAC3B,QAAI,QAAQ,YAAY;AACtB,UAAI,QAAS,SAAQ,KAAK,OAAO;AACjC,gBAAU,EAAE,MAAM,MAAM;AACxB;AAAA,IACF;AACA,QAAI,CAAC,QAAS;AACd,QAAI,QAAQ,SAAU,SAAQ,SAAS;AACvC,QAAI,QAAQ,OAAQ,SAAQ,OAAO;AACnC,QAAI,QAAQ,OAAQ,SAAQ,OAAO;AAAA,EACrC;AACA,MAAI,QAAS,SAAQ,KAAK,OAAO;AACjC,SAAO;AACT;AAEA,SAAS,oBAAoB,cAAsB,cAA+B;AAChF,QAAM,MAAMC,OAAK,SAASA,OAAK,QAAQ,YAAY,GAAGA,OAAK,QAAQ,YAAY,CAAC;AAChF,SAAO,QAAQ,MAAM,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,OAAK,WAAW,GAAG;AACpE;AAEA,SAAS,gBAAgB,cAAsB,UAA2B;AACxE,MAAI;AACF,UAAM,YAAY,IAAI,UAAU,CAAC,MAAM,cAAc,UAAU,aAAa,GAAG;AAAA,MAC7E,cAAc;AAAA,IAChB,CAAC;AACD,WAAO,CAAC,OAAO,aAAa,EAAE,EAAE,KAAK;AAAA,EACvC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,gCAAgC,MAA8C;AAC5F,MAAI,CAAC,KAAK,kBAAkB,CAACF,aAAW,KAAK,YAAY,EAAG,QAAO,CAAC;AAEpE,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,QAAI,MAAM,IAAI,KAAM,OAAM,IAAIE,OAAK,QAAQ,MAAM,IAAI,IAAI,CAAC;AAAA,EAC5D;AAEA,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,iBAAa,IAAIA,OAAK,QAAQ,MAAM,YAAY,CAAC;AAAA,EACnD;AAEA,QAAM,aAAiC,CAAC;AACxC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,YAAY,OAAO;AAC5B,QAAI;AACJ,QAAI;AACF,kBAAY,IAAI,UAAU,CAAC,YAAY,QAAQ,aAAa,GAAG,EAAE,cAAc,KAAK,CAAC;AAAA,IACvF,QAAQ;AACN;AAAA,IACF;AACA,UAAM,YAAY,uBAAuB,SAAS;AAClD,eAAW,MAAM,WAAW;AAC1B,YAAM,WAAWA,OAAK,QAAQ,GAAG,IAAI;AACrC,UAAI,aAAaA,OAAK,QAAQ,QAAQ,EAAG;AACzC,UAAI,CAAC,oBAAoB,UAAU,KAAK,YAAY,EAAG;AACvD,UAAI,aAAa,IAAI,QAAQ,EAAG;AAChC,UAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,UAAI,CAACF,aAAW,QAAQ,EAAG;AAC3B,UAAI,CAAC,gBAAgB,UAAU,QAAQ,EAAG;AAE1C,YAAM,MAAME,OAAK,SAAS,KAAK,cAAc,QAAQ;AACrD,YAAM,QAAQ,IAAI,MAAMA,OAAK,GAAG;AAChC,YAAM,QAAQ,MAAM,CAAC;AACrB,YAAM,SAAS,MAAM,CAAC,KAAK;AAC3B,WAAK,IAAI,QAAQ;AACjB,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,OAAOC,WAAU,UAAU,KAAK,GAAG;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACjHA;AAQA;AATA,OAAOC,YAAU;AA2BV,SAAS,qBAAqB,aAAmD;AACtF,QAAM,QAAQ,oBAAI,IAA6B;AAC/C,aAAW,OAAO,6BAA6B,WAAW,GAAG;AAC3D,eAAW,QAAQ,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC,GAAG;AACjD,YAAM,aAAaC,OAAK;AAAA,QACtB,eAAe,aAAa,IAAI,EAAE;AAAA,QAClC;AAAA,QACA,SAAS,IAAI;AAAA,QACb;AAAA,MACF;AACA,YAAM,SAAS,SAA0C,YAAY,MAAS;AAC9E,UAAI,CAAC,QAAQ,aAAc;AAC3B,YAAM,IAAIA,OAAK,QAAQ,OAAO,YAAY,GAAG;AAAA,QAC3C;AAAA,QACA,cAAcA,OAAK,QAAQ,OAAO,YAAY;AAAA,QAC9C,OAAO,IAAI;AAAA,QACX,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;;;ACxCA,SAAS,QAAQ,MAAuB;AACtC,QAAM,IAAI,QAAQ,IAAI,IAAI;AAC1B,SAAO,MAAM,OAAO,MAAM,UAAU,MAAM;AAC5C;AAEA,SAAS,MAAM,MAAc,UAA0B;AACrD,QAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,OAAO,GAAG;AACpB,SAAO,OAAO,SAAS,CAAC,KAAK,KAAK,IAAI,IAAI;AAC5C;AAsBO,SAAS,wBACd,UAAiC,CAAC,GACR;AAC1B,QAAM,UACJ,QAAQ,YAAY,QACnB,QAAQ,YAAY,SAAS,QAAQ,wBAAwB;AAChE,QAAMC,qBACJ,QAAQ,sBAAsB,SAAS,CAAC,QAAQ,8BAA8B;AAChF,QAAM,mBACJ,QAAQ,oBACR,MAAM,sCAAsC,2BAA2B;AACzE,QAAM,iBACJ,QAAQ,kBACR,MAAM,mCAAmC,CAAC;AAC5C,QAAM,yBACJ,QAAQ,0BACR,MAAM,4CAA4C,iCAAiC;AACrF,QAAM,sBACJ,QAAQ,uBACR,MAAM,yCAAyC,8BAA8B;AAC/E,QAAM,qBACJ,QAAQ,sBACR,MAAM,wCAAwC,6BAA6B;AAC7E,QAAM,iBACJ,QAAQ,mBAAmB,QAAQ,QAAQ,gCAAgC;AAC7E,QAAM,WAAW,QAAQ,0BAA0B,KAAK,QAAQ,IAAI,yBAAyB;AAC7F,QAAM,cAAc,WAChB,QAAQ,cACR,QAAQ,gBAAgB,QAAQ,IAAI,yBAAyB;AACjE,QAAM,eAAe,QAAQ,iBAAiB,SAAS,CAAC,QAAQ,qCAAqC;AACrG,QAAM,gBAAgB,MAAM,oCAAoC,GAAK;AACrE,QAAM,wBACJ,QAAQ,0BAA0B,SAC9B,QAAQ,wBACR,eACE,gBAAgB,IACd,gBACA,OACF;AACR,QAAM,aAAa,MAAM,iCAAiC,GAAK;AAC/D,QAAM,yBACJ,QAAQ,2BACP,OAAO,SAAS,UAAU,KAAK,aAAa,IAAI,KAAK,MAAM,UAAU,IAAI;AAE5E,SAAO;AAAA,IACL;AAAA,IACA,mBAAAA;AAAA,IACA;AAAA,IACA,gBAAgB,iBAAiB,IAAI,iBAAiB;AAAA,IACtD,wBAAwB,0BAA0B,IAAI,yBAAyB;AAAA,IAC/E,qBAAqB,uBAAuB,IAAI,sBAAsB;AAAA,IACtE,oBACE,OAAO,SAAS,kBAAkB,KAAK,qBAAqB,IACxD,KAAK,MAAM,kBAAkB,IAC7B;AAAA,IACN;AAAA,IACA,aAAa,cAAc,OAAO,WAAW,IAAI;AAAA,IACjD;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACrGA;AAFA,SAAS,cAAAC,cAAY,YAAAC,kBAAgB;AACrC,OAAOC,YAAU;AAKjB,IAAM,6BAA6B,KAAK,KAAK;AAkBtC,SAAS,2BACd,OAC0B;AAC1B,QAAM,MAAM,MAAM,OAAO,KAAK,IAAI;AAClC,QAAM,mBAAmB,MAAM,oBAAoB;AAEnD,MAAI,CAACC,aAAW,MAAM,YAAY,EAAG,QAAO;AAE5C,MAAI,MAAM,SAAS,MAAM,YAAY;AACnC,UAAM,gBAAgBC,OAAK;AAAA,MACzB,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQC,WAAS,aAAa,EAAE;AACtC,UAAI,MAAM,QAAQ,iBAAkB,QAAO;AAAA,IAC7C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,SAASD,OAAK,KAAK,MAAM,cAAc,MAAM;AACnD,MAAI,CAACD,aAAW,MAAM,EAAG,QAAO;AAEhC,QAAM,YAAY,WAAW,MAAM,cAAc,CAAC,UAAU,aAAa,CAAC;AAC1E,MAAI,UAAU,WAAW,EAAG,QAAO;AACnC,QAAM,aAAa,UAAU,OAC1B,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AACnC,MAAI,wBAAwB,UAAU,EAAE,SAAS,EAAG,QAAO;AAE3D,QAAM,gBAAgB,WAAW,MAAM,cAAc;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,cAAc,WAAW,GAAG;AAC9B,UAAM,QAAQ,OAAO,cAAc,OAAO,KAAK,CAAC;AAChD,QAAI,OAAO,SAAS,KAAK,KAAK,QAAQ,EAAG,QAAO;AAAA,EAClD;AAEA,QAAM,YAAY,WAAW,MAAM,cAAc;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,UAAU,WAAW,GAAG;AAE1B,QAAI,cAAc,WAAW,EAAG,QAAO;AACvC,WAAO;AAAA,EACT;AACA,QAAM,YAAY,OAAO,UAAU,OAAO,KAAK,CAAC;AAChD,MAAI,OAAO,SAAS,SAAS,KAAK,YAAY,EAAG,QAAO;AAExD,SAAO;AACT;;;AClFA;AAFA,SAAS,cAAAG,cAAY,eAAAC,eAAa,YAAAC,kBAAgB;AAClD,OAAOC,YAAU;AA8BV,SAAS,uBAAuB,OAAoB,CAAC,GAA2B;AACrF,QAAM,cAAc,qBAAqB,KAAK,eAAe,mBAAmB,CAAC;AACjF,QAAM,eAAe,oBAAoB,WAAW;AACpD,QAAM,MAAM,KAAK,OAAO,KAAK,IAAI;AACjC,QAAM,YAAY,IAAI,KAAK,GAAG,EAAE,YAAY;AAE5C,MAAI,CAACC,aAAW,YAAY,GAAG;AAC7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAA4B;AAChC,MAAI,WAAW;AACf,MAAI,cAAc;AAClB,MAAI,WAA0B;AAE9B,MAAI;AACJ,MAAI;AACF,cAAUC,cAAY,cAAc,EAAE,eAAe,KAAK,CAAC;AAAA,EAC7D,QAAQ;AACN,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,aAAW,YAAY,SAAS;AAC9B,QAAI,CAAC,SAAS,YAAY,EAAG;AAC7B,gBAAY;AACZ,UAAM,UAAUC,OAAK,KAAK,cAAc,SAAS,IAAI;AACrD,QAAI;AACF,YAAM,KAAKC,WAAS,OAAO;AAC3B,iBAAW,aAAa,OAAO,GAAG,UAAU,KAAK,IAAI,UAAU,GAAG,OAAO;AAAA,IAC3E,QAAQ;AAAA,IAER;AACA,QAAI;AACF,iBAAW,eAAeF,cAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACvE,YAAI,YAAY,YAAY,EAAG,gBAAe;AAAA,MAChD;AAAA,IACF,QAAQ;AAAA,IAER;AACA,QAAI,eAAe,QAAQ,KAAK,mBAAmB,MAAM;AACvD,YAAM,MAAM,KAAK,kBAAkB;AACnC,UAAI,OAAO,GAAG;AACZ,qBAAa;AAAA,MACf,OAAO;AACL,cAAM,WAAW,mBAAmB,SAAS,GAAG;AAChD,YAAI,aAAa,KAAM,cAAa;AAAA,YAC/B,eAAc;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA,aAAa,aAAa,OAAO,OAAO,IAAI,KAAK,QAAQ,EAAE,YAAY;AAAA,IACvE;AAAA,EACF;AACF;;;ACxGA;AAHA,SAAS,cAAAG,oBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,OAAOC,YAAU;AAIV,IAAM,gCAAgC;AAAA,EAC3C;AAAA,EACAA,OAAK,KAAKD,SAAQ,GAAG,aAAa,SAAS;AAC7C;AAEA,SAAS,QAAQ,MAAmB,OAAiB,WAAqC;AACxF,MAAI,CAAC,WAAW,KAAK,EAAG;AACxB,QAAM,WAAW,qBAAqB,UAAU,KAAK,CAAC;AACtD,MAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,OAAK,IAAI,QAAQ;AACjB,QAAM,KAAK,QAAQ;AACrB;AAMA,SAAS,yBAAyB,SAA+C;AAC/E,MAAI,QAAQ,iBAAiB,KAAM,QAAO,QAAQ;AAClD,MAAI,QAAQ,IAAI,WAAW,OAAQ,QAAO;AAC1C,SACE,QAAQ,IAAI,mCAAmC,OAC/C,CAAC,CAAC,KAAK,SAAS,IAAI,EAAE,UAAU,QAAQ,IAAI,kCAAkC,IAAI,YAAY,CAAC;AAEnG;AAEO,SAAS,wBACd,UAA6D,CAAC,GACpD;AACV,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAkB,CAAC;AAEzB,UAAQ,MAAM,OAAO,QAAQ,eAAe,mBAAmB,CAAC;AAEhE,QAAM,QAAQ,QAAQ,IAAI,4BAA4B,MAAM,GAAG,EAC5D,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACjB,aAAW,aAAa,SAAS,CAAC,EAAG,SAAQ,MAAM,OAAO,SAAS;AAEnE,MAAI,yBAAyB,OAAO,GAAG;AACrC,eAAW,aAAa,+BAA+B;AACrD,YAAM,WAAWC,OAAK,QAAQ,SAAS;AACvC,UAAI,CAAC,KAAK,IAAI,QAAQ,KAAKF,aAAW,QAAQ,EAAG,SAAQ,MAAM,OAAO,QAAQ;AAAA,IAChF;AAAA,EACF;AAEA,SAAO;AACT;;;ACpDA;AAIA,SAASG,SAAQ,MAAuB;AACtC,QAAM,IAAI,QAAQ,IAAI,IAAI;AAC1B,SAAO,MAAM,OAAO,MAAM,UAAU,MAAM;AAC5C;AAEA,SAAS,UAAU,MAAc,UAA0B;AACzD,QAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,OAAO,GAAG;AACpB,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AASO,SAAS,2BAA2B,QAA8B,CAAC,GAA6B;AACrG,QAAM,WAAW,MAAM,UAAU,KAAK,KAAK,QAAQ,IAAI,wBAAwB,KAAK,KAAK;AACzF,QAAM,iBAAiB,UAAU,sCAAsC,EAAE;AACzE,QAAM,WAAW,sBAAsB;AAAA,IACrC,GAAG;AAAA,IACH;AAAA,IACA,oBAAoB,MAAM,sBAAsB;AAAA,EAClD,CAAC;AACD,MAAI,YAAY,CAAC,SAAS,MAAM,SAAS,eAAe;AASxD,QAAM,QAAQ,QAAQ,IAAI,oCAAoC,KAAK,EAAE,YAAY;AACjF,MAAI,UAAU,UAAU,UAAU,SAAS,UAAU,IAAK,aAAY;AAAA,WAC7D,UAAU,eAAe,UAAU,QAAQ,UAAU,IAAK,aAAY;AAE/E,SAAO,EAAE,UAAU,WAAW,eAAe;AAC/C;AAMO,SAAS,6BACd,WACA,UAC0B;AAC1B,MAAI,CAAC,SAAS,UAAW,QAAO;AAChC,QAAM,oBACJ,UAAU,WAAW,CAACA,SAAQ,oCAAoC;AACpE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS;AAAA,IACT,kBAAkB;AAAA;AAAA;AAAA;AAAA,IAIlB,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,wBAAwB;AAAA,IACxB,qBAAqB;AAAA,IACrB,gBAAgB,UAAU,iBAAiB,IAAI,UAAU,iBAAiB;AAAA,IAC1E,cAAc;AAAA,IACd,UAAU,SAAS;AAAA,EACrB;AACF;;;ACzEO,SAAS,oBAAoB,OAAe,QAAuB;AACxE,MAAI,QAAQ,IAAI,yBAAyB,IAAK;AAC9C,QAAM,SAAS,SAAS,KAAK,MAAM,KAAK;AACxC,UAAQ,MAAM,oBAAoB,KAAK,GAAG,MAAM,EAAE;AACpD;;;ACLA;AAGO,IAAM,qBAAN,MAAyB;AAAA,EACb,cAAc,oBAAI,IAA2B;AAAA,EAE9D,iBAAiB,cAAsB,OAAO,eAA8B;AAC1E,UAAM,MAAM,GAAG,YAAY,KAAK,IAAI;AACpC,QAAI,KAAK,YAAY,IAAI,GAAG,EAAG,QAAO,KAAK,YAAY,IAAI,GAAG,KAAK;AACnE,UAAM,SAAS,WAAW,cAAc,CAAC,YAAY,WAAW,GAAG,IAAI,QAAQ,CAAC;AAChF,QAAI,OAAO,WAAW,GAAG;AACvB,WAAK,YAAY,IAAI,KAAK,IAAI;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,OAAO,OAAO,OAAO,KAAK,CAAC;AACzC,UAAM,SAAS,OAAO,SAAS,KAAK,IAAI,QAAQ;AAChD,SAAK,YAAY,IAAI,KAAK,MAAM;AAChC,WAAO;AAAA,EACT;AACF;;;ACnBA;AAGO,IAAM,wBAAN,MAA4B;AAAA,EAChB,QAAQ,oBAAI,IAAsB;AAAA,EAEnD,UAAU,cAAgC;AACxC,UAAM,WAAW;AACjB,UAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,QAAI,WAAW,OAAW,QAAO;AACjC,UAAM,QAAQ,eAAe,QAAQ;AACrC,SAAK,MAAM,IAAI,UAAU,KAAK;AAC9B,WAAO;AAAA,EACT;AACF;;;ACVO,IAAM,0BAAN,MAA8B;AAAA,EAClB,QAAQ,oBAAI,IAA2B;AAAA,EAExD,OAAO,KAAsC;AAC3C,UAAM,SAAS,KAAK,MAAM,IAAI,IAAI,EAAE;AACpC,QAAI,WAAW,OAAW,QAAO;AACjC,UAAM,UAAU,wBAAwB,GAAG;AAC3C,SAAK,MAAM,IAAI,IAAI,IAAI,OAAO;AAC9B,WAAO;AAAA,EACT;AACF;;;ACRA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AA0B7B,SAAS,iBAAiB,SAAuF;AAC/G,QAAM,SAAqD,CAAC;AAC5D,aAAW,UAAU,SAAS;AAC5B,WAAO,OAAO,IAAI,KAAK,OAAO,OAAO,IAAI,KAAK,KAAK;AAAA,EACrD;AACA,SAAO;AACT;AAGO,SAAS,2BACd,SACA,UAAkE,CAAC,GAC5C;AACvB,QAAM,aAAa,QAAQ,oBAAoB;AAC/C,QAAM,WAAW,QAAQ,kBAAkB;AAE3C,SAAO;AAAA,IACL,aAAa,QAAQ;AAAA,IACrB,WAAW,QAAQ;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,WAAW,QAAQ;AAAA,IACnB,eAAe,QAAQ,cAAc;AAAA,IACrC,aAAa,QAAQ,QAAQ;AAAA,IAC7B,aAAa,iBAAiB,QAAQ,OAAO;AAAA,IAC7C,QAAQ,QAAQ;AAAA,IAChB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACtD,GAAI,QAAQ,oBAAoB,SAAS,EAAE,oBAAoB,QAAQ,mBAAmB,IAAI,CAAC;AAAA,IAC/F,GAAI,QAAQ,yBAAyB,OAAO,EAAE,uBAAuB,QAAQ,sBAAsB,IAAI,CAAC;AAAA,IACxG,eAAe,QAAQ,QAAQ,MAAM,GAAG,UAAU,EAAE,IAAI,CAAC,YAAY;AAAA,MACnE,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,GAAI,OAAO,aAAa,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;AAAA,MAC7D,GAAI,OAAO,SAAS,OAAO,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MACtD,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC9C,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IACnD,EAAE;AAAA,IACF,aAAa,QAAQ,MAAM,MAAM,GAAG,QAAQ;AAAA,EAC9C;AACF;;;AnCvBA,SAAS,aAAa,UAAiC,CAAC,GAAG;AACzD,QAAM,cAAc,QAAQ,cACxB,qBAAqB,QAAQ,WAAW,IACxC,mBAAmB;AACvB,QAAM,YAAY,wBAAwB,EAAE,YAAY,CAAC;AACzD,QAAM,MAAM,QAAQ,OAAO,KAAK,IAAI;AACpC,SAAO,EAAE,aAAa,WAAW,IAAI;AACvC;AAEA,SAAS,mBAAmB,MAAyE;AACnG,MAAI,OAAO,SAAS,SAAU,QAAO,EAAE,QAAQ,KAAK;AACpD,SAAO;AACT;AAEA,SAAS,WACP,OACA,WACA,QACA,QACM;AACN,QAAM,KAAK,EAAE,MAAM,WAAW,QAAQ,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG,CAAC;AACvE;AAEA,SAAS,qBACP,WACA,cACA,cACkB;AAClB,MAAI,CAAC,gBAAgB,UAAU,SAAS,KAAM,QAAO;AACrD,SAAO,EAAE,GAAG,WAAW,OAAO,mBAAmB,UAAU,MAAM,YAAY,EAAE;AACjF;AAEA,SAAS,iBACP,SACA,OAC4C;AAC5C,QAAM,SAAqD,CAAC;AAC5D,aAAW,QAAQ,OAAO;AACxB,WAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,KAAK,KAAK;AAAA,EACrD;AACA,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,YAAY;AACrB,aAAO,OAAO,UAAU,KAAK,OAAO,OAAO,UAAU,KAAK,KAAK;AAAA,IACjE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,WAA6B,SAAiC;AACjG,MAAI,UAAU,SAAS,oBAAqB,QAAO,gBAAgB,WAAW,OAAO;AACrF,SAAO,kBAAkB,WAAW,OAAO;AAC7C;AAEA,SAAS,4BACP,WACA,aACA,cAC0B;AAC1B,MAAI,UAAU,SAAS,qBAAqB;AAC1C,WAAO,uBAAuB,UAAU,MAAM,aAAa,YAAY;AAAA,EACzE;AACA,SAAO,yBAAyB,UAAU,MAAM,aAAa,YAAY;AAC3E;AAEA,SAAS,qBAAqB,WAAmD;AAC/E,QAAM,SAAS,oBAAI,IAA6B;AAChD,aAAW,QAAQ,WAAW;AAC5B,eAAW,CAAC,KAAK,KAAK,KAAK,qBAAqB,IAAI,EAAG,QAAO,IAAI,KAAK,KAAK;AAAA,EAC9E;AACA,SAAO;AACT;AAEA,SAAS,yBACP,WACA,cACQ;AACR,MAAI,UAAU,SAAS,UAAU,QAAQ;AACvC,WAAOC,OAAK,KAAK,cAAc,UAAU,OAAO,UAAU,MAAM;AAAA,EAClE;AACA,SAAOA,OAAK,QAAQ,UAAU,MAAM,IAAI;AAC1C;AAEO,SAAS,kBAAkB,UAAiC,CAAC,GAA0B;AAC5F,MAAI,YAAY,wBAAwB,OAAO;AAC/C,QAAM,eAAe,2BAA2B;AAChD,cAAY,6BAA6B,WAAW,YAAY;AAEhE,QAAM,QAAQ,aAAa,OAAO;AAClC,sBAAoB,QAAQ,GAAG,MAAM,UAAU,MAAM,kBAAkB;AACvE,QAAM,eAAe,4BAA4B,MAAM,WAAW,MAAM,GAAG;AAE3E,QAAM,gBAAgB,UAAU,oBAC5B,kBAAkB,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,MAAM,EAAE,MAAM,IAAI,EAAE,GAAG,EAAE,IAC3E,CAAC;AACL,MAAI,cAAc,SAAS,GAAG;AAC5B,wBAAoB,YAAY,GAAG,cAAc,MAAM,+BAA+B;AAAA,EACxF;AAEA,sBAAoB,SAAS,yBAAyB;AACtD,QAAM,QAAQ,qBAAqB,MAAM,SAAS;AAClD,sBAAoB,SAAS,GAAG,MAAM,IAAI,sBAAsB;AAChE,QAAM,WAAW;AAAA,IACf,kBAAkB,IAAI,wBAAwB;AAAA,IAC9C,gBAAgB,IAAI,sBAAsB;AAAA,IAC1C,aAAa,IAAI,mBAAmB;AAAA,EACtC;AAEA,QAAM,QAAwC,CAAC;AAC/C,QAAM,UAA2B,CAAC;AAClC,QAAM,iBAAiB,oBAAI,IAAY;AACvC,QAAM,aAAa,UAAU;AAE7B,QAAM,aAAa,MAAe,QAAQ,UAAU;AAEpD,aAAW,eAAe,MAAM,WAAW;AACzC,QAAI,WAAW,EAAG;AAClB,wBAAoB,QAAQ,WAAW;AACvC,UAAM,eAAeA,OAAK,KAAK,aAAa,WAAW;AACvD,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA,kBAAkB,UAAU;AAAA,MAC5B,gBAAgB,UAAU;AAAA,MAC1B,gBAAgB,UAAU;AAAA,MAC1B,aAAa,UAAU;AAAA,MACvB;AAAA,MACA,KAAK,MAAM;AAAA,IACb;AAEA,UAAM,uBAAuB,8BAA8B,QAAQ;AACnE,wBAAoB,cAAc,GAAG,qBAAqB,MAAM,0BAA0B,WAAW,EAAE;AACvG,QAAI,sBAAsB;AAC1B,eAAW,OAAO,sBAAsB;AACtC,UAAI,WAAW,EAAG;AAClB,6BAAuB;AACvB,UAAI,sBAAsB,OAAO,GAAG;AAClC,4BAAoB,cAAc,GAAG,mBAAmB,IAAI,qBAAqB,MAAM,YAAY;AAAA,MACrG;AACA,YAAM,WAAWA,OAAK,QAAQ,IAAI,IAAI;AACtC,UAAI,eAAe,IAAI,QAAQ,EAAG;AAClC,qBAAe,IAAI,QAAQ;AAC3B,YAAM,YAA8B,EAAE,GAAG,KAAK,MAAM,SAAS;AAE7D,YAAM,WAAW,4BAA4B,WAAW,aAAa,YAAY;AACjF,UAAI,UAAU;AACZ,mBAAW,OAAO,UAAU,MAAM,QAAQ;AAC1C,gBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,SAAS,CAAC;AACnF;AAAA,MACF;AACA,YAAM,eAAe,yBAAyB,WAAW,YAAY;AACrE,YAAM,UAAU,MAAM,IAAIA,OAAK,QAAQ,YAAY,CAAC,KAAK;AACzD,YAAM,cAAc,2BAA2B;AAAA,QAC7C;AAAA,QACA,gBAAgB;AAAA,QAChB,kBAAkB,UAAU;AAAA,QAC5B,OAAO,UAAU;AAAA,QACjB;AAAA,QACA,qBAAqB,aAAa;AAAA,QAClC,cAAc,UAAU;AAAA,QACxB,gBAAgB,SAAS;AAAA,MAC3B,CAAC;AACD,UAAI,aAAa;AACf,mBAAW,OAAO,UAAU,MAAM,WAAW;AAC7C,gBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,YAAY,CAAC;AACtF;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,UACE,qBAAqB,WAAW,UAAU,cAAc,UAAU,sBAAsB;AAAA,UACxF,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,eAAW,OAAO,yBAAyB,QAAQ,GAAG;AACpD,UAAI,WAAW,EAAG;AAClB,YAAM,WAAWA,OAAK,QAAQ,IAAI,IAAI;AACtC,UAAI,eAAe,IAAI,QAAQ,EAAG;AAClC,qBAAe,IAAI,QAAQ;AAC3B,YAAM,YAA8B,EAAE,GAAG,KAAK,MAAM,SAAS;AAE7D,YAAM,WAAW,wBAAwB,UAAU,MAAM,aAAa,YAAY;AAClF,UAAI,UAAU;AACZ,mBAAW,OAAO,UAAU,MAAM,QAAQ;AAC1C,gBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,SAAS,CAAC;AACnF;AAAA,MACF;AACA,YAAM,eAAe,yBAAyB,WAAW,YAAY;AACrE,YAAM,UAAU,MAAM,IAAIA,OAAK,QAAQ,YAAY,CAAC,KAAK;AACzD,YAAM,cAAc,sBAAsB;AAAA,QACxC;AAAA,QACA,gBAAgB;AAAA,QAChB,kBAAkB,UAAU;AAAA,QAC5B,OAAO,UAAU;AAAA,QACjB;AAAA,QACA,qBAAqB,aAAa;AAAA,QAClC,cAAc,UAAU;AAAA,QACxB,gBAAgB,SAAS;AAAA,MAC3B,CAAC;AACD,UAAI,aAAa;AACf,mBAAW,OAAO,UAAU,MAAM,WAAW;AAC7C,gBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,YAAY,CAAC;AACtF;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,UACE,qBAAqB,WAAW,UAAU,cAAc,UAAU,sBAAsB;AAAA,UACxF,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,UAAM,qBAAqB;AAAA,MACzB,GAAG,uBAAuB,QAAQ;AAAA,MAClC,GAAG,gCAAgC,QAAQ;AAAA,IAC7C;AACA,wBAAoB,aAAa,GAAG,mBAAmB,MAAM,oBAAoB,WAAW,EAAE;AAC9F,UAAM,eAAe,oBAAI,IAAY;AACrC,QAAI,oBAAoB;AACxB,eAAW,OAAO,oBAAoB;AACpC,UAAI,WAAW,EAAG;AAClB,2BAAqB;AACrB,UAAI,oBAAoB,OAAO,GAAG;AAChC,4BAAoB,aAAa,GAAG,iBAAiB,IAAI,mBAAmB,MAAM,YAAY;AAAA,MAChG;AACA,YAAM,WAAWA,OAAK,QAAQ,IAAI,IAAI;AACtC,UAAI,aAAa,IAAI,QAAQ,EAAG;AAChC,mBAAa,IAAI,QAAQ;AACzB,YAAM,YAA8B,EAAE,GAAG,KAAK,MAAM,SAAS;AAC7D,YAAM,UAAU,MAAM,IAAIA,OAAK,QAAQ,UAAU,IAAI,CAAC,KAAK;AAC3D,YAAM,eAAe,UACjB,OACA,2BAA2B;AAAA,QACzB,cAAc,UAAU;AAAA,QACxB;AAAA,QACA,OAAO,UAAU;AAAA,QACjB,YAAY,UAAU;AAAA,QACtB,KAAK,MAAM;AAAA,MACb,CAAC;AACL,YAAM,YAAY,oBAAoB;AAAA,QACpC;AAAA,QACA,cAAcA,OAAK,QAAQ,UAAU,IAAI;AAAA,QACzC,gBAAgB,UAAU;AAAA,QAC1B,gBAAgB,UAAU;AAAA,QAC1B,wBAAwB,UAAU;AAAA,QAClC,OAAO,UAAU;AAAA,QACjB;AAAA,QACA,sBAAsB,QAAQ;AAAA,QAC9B;AAAA,MACF,CAAC;AACD,UAAI,WAAW;AACb,cAAM,EAAE,QAAQ,aAAa,QAAQ,YAAY,IAAI,mBAAmB,SAAS;AACjF,mBAAW,OAAO,UAAU,MAAM,aAAa,WAAW;AAC1D,gBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,YAAY,CAAC;AACtF;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,UACE,qBAAqB,WAAW,UAAU,cAAc,UAAU,sBAAsB;AAAA,UACxF,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,KAAK,UAAU,uBAAuB,GAAG;AACvD,iBAAW,OAAO,gCAAgC;AAAA,QAChD;AAAA,QACA;AAAA,QACA,qBAAqB,UAAU;AAAA,QAC/B,aAAa,UAAU;AAAA,QACvB;AAAA,QACA,KAAK,MAAM;AAAA,MACb,CAAC,GAAG;AACF,YAAI,WAAW,EAAG;AAClB,cAAM,WAAWA,OAAK,QAAQ,IAAI,IAAI;AACtC,YAAI,eAAe,IAAI,QAAQ,EAAG;AAClC,uBAAe,IAAI,QAAQ;AAC3B,cAAM,YAA8B,EAAE,GAAG,KAAK,MAAM,SAAS;AAC7D,cAAM,QAAQ,UAAU,SAASA,OAAK,SAAS,QAAQ;AACvD,cAAM,UAAU,wBAAwB;AAAA,UACtC;AAAA,UACA;AAAA,UACA,SAAS;AAAA,UACT,OAAO,UAAU;AAAA,UACjB,qBAAqB,UAAU;AAAA,UAC/B;AAAA,QACF,CAAC;AACD,YAAI,SAAS;AACX,qBAAW,OAAO,UAAU,MAAM,OAAO;AACzC,kBAAQ,KAAK,EAAE,GAAG,WAAW,UAAU,OAAO,SAAS,MAAM,YAAY,QAAQ,CAAC;AAClF;AAAA,QACF;AACA,gBAAQ;AAAA,UACN;AAAA,YACE,qBAAqB,WAAW,UAAU,cAAc,UAAU,sBAAsB;AAAA,YACxF,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,iBAAiB;AACrB,MAAI,wBAAwB;AAC5B,MAAI,mBAAmB;AACvB,MAAI,eAAe;AACnB,MAAI,eAAe;AACnB,MAAI,eAAe;AACnB,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,MAAO,mBAAkB,OAAO;AAC3C,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,YAAY,OAAO,MAAO,qBAAoB,OAAO;AACpF,QAAI,OAAO,UAAU;AACnB,sBAAgB;AAChB,sBAAgB,OAAO,SAAS;AAChC,UAAI,OAAO,SAAS,uBAAwB,0BAAyB;AAAA,IACvE,WAAW,OAAO,SAAS;AACzB,sBAAgB;AAChB,UAAI,OAAO,eAAe,aAAa,OAAO,MAAO,qBAAoB,OAAO;AAAA,IAClF;AAAA,EACF;AAEA,QAAM,UAAU,UAAU,eACtB,uBAAuB;AAAA,IACrB,aAAa,MAAM;AAAA,IACnB,KAAK,MAAM;AAAA,IACX,gBAAgB,UAAU;AAAA,EAC5B,CAAC,IACD;AACJ;AAAA,IACE;AAAA,IACA,GAAG,QAAQ,MAAM,eAAe,YAAY,aAAa,YAAY;AAAA,EACvE;AAEA,QAAM,qBAAqB,0BAA0B,SAAS,KAAK;AACnE,QAAM,iBAAiB,2BAA2B;AAAA,IAChD,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,QAAQ,CAAC,UAAU;AAAA,IACnB,SAAS,UAAU;AAAA,IACnB,kBAAkB,UAAU;AAAA,IAC5B,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,UAAU;AAAA,IAC1B,cAAc,UAAU;AAAA,IACxB,UAAU,UAAU,WAChB;AAAA,MACE,IAAI,UAAU,SAAS;AAAA,MACvB,MAAM,UAAU,SAAS;AAAA,MACzB,WAAW,UAAU,SAAS;AAAA,MAC9B,aAAa,UAAU,SAAS;AAAA,MAChC,QAAQ,UAAU,SAAS;AAAA,IAC7B,IACA;AAAA,IACJ,WAAW,IAAI,KAAK,MAAM,GAAG,EAAE,YAAY;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,iBAAiB,SAAS,KAAK;AAAA,IAC9C;AAAA,IACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,mBAAmB,SAAS,IAAI,EAAE,mBAAmB,IAAI,CAAC;AAAA,IAC9D,GAAI,wBAAwB,IAAI,EAAE,sBAAsB,IAAI,CAAC;AAAA,EAC/D,CAAC;AAED,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,QAAQ,CAAC,UAAU;AAAA,IACnB,SAAS,UAAU;AAAA,IACnB,kBAAkB,UAAU;AAAA,IAC5B,gBAAgB,UAAU;AAAA,IAC1B,gBAAgB,UAAU;AAAA,IAC1B,cAAc,UAAU;AAAA,IACxB,UAAU,UAAU,WAChB;AAAA,MACE,IAAI,UAAU,SAAS;AAAA,MACvB,MAAM,UAAU,SAAS;AAAA,MACzB,WAAW,UAAU,SAAS;AAAA,MAC9B,aAAa,UAAU,SAAS;AAAA,MAChC,QAAQ,UAAU,SAAS;AAAA,IAC7B,IACA;AAAA,IACJ,WAAW,IAAI,KAAK,MAAM,GAAG,EAAE,YAAY;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,iBAAiB,SAAS,KAAK;AAAA,IAC9C;AAAA,IACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,mBAAmB,SAAS,IAAI,EAAE,mBAAmB,IAAI,CAAC;AAAA,IAC9D,GAAI,wBAAwB,IAAI,EAAE,sBAAsB,IAAI,CAAC;AAAA,IAC7D;AAAA,EACF;AACF;",
|
|
4
|
+
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\n\r\nexport function fail(message: string): never {\r\n console.error(message);\r\n process.exit(1);\r\n}\r\n\r\n/** Avoid flashing a visible console on Windows when spawning worker/sidecar children. */\r\nexport function hiddenSpawnOptions<T extends Record<string, unknown>>(opts: T): T {\r\n if (process.platform !== \"win32\") return opts;\r\n return { windowsHide: true, ...opts };\r\n}\r\n\r\nexport function required(value: string | undefined, name: string): string {\r\n if (!value) fail(`missing ${name}`);\r\n return value;\r\n}\r\n\r\nexport function safeJson(line: string): unknown {\r\n try {\r\n return JSON.parse(line);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function readJson<T>(file: string, fallback?: T): T {\r\n try {\r\n return JSON.parse(readFileSync(file, \"utf8\")) as T;\r\n } catch (error) {\r\n if (arguments.length > 1) return fallback as T;\r\n fail(`failed to read ${file}: ${(error as Error).message}`);\r\n }\r\n}\r\n\r\nexport function writeJson(file: string, value: unknown): void {\r\n mkdirSync(path.dirname(file), { recursive: true });\r\n writeFileSync(file, `${JSON.stringify(value, null, 2)}\\n`);\r\n}\r\n\r\nexport function safeSlug(value: string | undefined): string {\r\n return (\r\n String(value || \"\")\r\n .toLowerCase()\r\n .replace(/[^a-z0-9._-]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\") || \"worker\"\r\n );\r\n}\r\n\r\nexport function timestampSlug(name: string): string {\r\n return safeSlug(`${new Date().toISOString().replace(/[-:]/g, \"\").replace(/\\..+/, \"Z\")}-${name}`);\r\n}\r\n\r\nexport function splitCsv(value: string | undefined): string[] {\r\n return value ? String(value).split(\",\").map((item) => item.trim()).filter(Boolean) : [];\r\n}\r\n\r\nexport function trimTrailingSlash(url: string): string {\r\n return String(url).replace(/\\/+$/, \"\");\r\n}\r\n\r\nexport function oneLine(value: string): string {\r\n return String(value || \"\")\r\n .replace(/\\s+/g, \" \")\r\n .trim();\r\n}\r\n\r\nexport function fileSize(file: string): number {\r\n try {\r\n return statSync(file).size;\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nexport function fileMtime(file: string): string | null {\r\n try {\r\n return statSync(file).mtime.toISOString();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function tailFile(file: string, lines: number): string {\r\n if (!existsSync(file)) return \"\";\r\n const data = readFileSync(file, \"utf8\");\r\n return data.split(\"\\n\").slice(-lines).join(\"\\n\");\r\n}\r\n\r\nexport function readMaybeFile(file: string | undefined): string {\r\n return file ? readFileSync(path.resolve(file), \"utf8\") : \"\";\r\n}\r\n\r\nexport function listRunIds(runsDir: string): string[] {\r\n if (!existsSync(runsDir)) return [];\r\n return readdirSync(runsDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n}\r\n\r\nexport function sleepMs(ms: number): void {\r\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\r\n}\r\n\r\n/** Non-blocking sleep for async loops (daemon backoff, interruptible shutdown). */\r\nexport function sleepMsAsync(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport function isPidAlive(pid: number | undefined): boolean {\r\n if (!pid) return false;\r\n try {\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function killWorkerProcess(pid: number, signal: NodeJS.Signals): void {\r\n try {\r\n process.kill(-pid, signal);\r\n } catch {\r\n process.kill(pid, signal);\r\n }\r\n}\r\n\r\nexport function latestIso(values: Array<string | null | undefined>): string | null {\r\n let best: string | null = null;\r\n let bestMs = -Infinity;\r\n for (const value of values) {\r\n if (!value) continue;\r\n const ms = Date.parse(value);\r\n if (Number.isFinite(ms) && ms > bestMs) {\r\n bestMs = ms;\r\n best = value;\r\n }\r\n }\r\n return best;\r\n}\r\n\r\nexport function secsAgo(ms: number): number {\r\n return Math.max(0, Math.round((Date.now() - ms) / 1000));\r\n}\r\n", "/**\r\n * Worker spawn env scrub \u2014 harness workers must not inherit host deployment secrets.\r\n */\r\n\r\n/** Exact env keys that must never reach a worker child process. */\r\nexport const FORBIDDEN_WORKER_ENV_KEYS = [\r\n \"ANTHROPIC_API_KEY\",\r\n \"ANALYST_API_KEY\",\r\n \"RECRUITER_API_KEY\",\r\n \"AUTH_SECRET\",\r\n \"NEXTAUTH_SECRET\",\r\n \"DATABASE_URL\",\r\n \"PRODUCTION_DATABASE_URL\",\r\n \"KYNVER_PRODUCTION_DATABASE_URL\",\r\n \"REDIS_URL\",\r\n \"GOOGLE_CLIENT_SECRET\",\r\n \"GITHUB_CLIENT_SECRET\",\r\n \"KYNVER_API_KEY\",\r\n \"KYNVER_SERVICE_SECRET\",\r\n \"KYNVER_RUNTIME_SECRET\",\r\n \"KYNVER_CRON_SECRET\",\r\n \"OPENCLAW_CRON_SECRET\",\r\n \"QSTASH_TOKEN\",\r\n \"QSTASH_CURRENT_SIGNING_KEY\",\r\n \"QSTASH_NEXT_SIGNING_KEY\",\r\n \"TOOL_SECRETS_KEK\",\r\n \"TOOL_EXECUTOR_DISPATCH_SECRET\",\r\n \"CLOUDFLARE_API_TOKEN\",\r\n \"STRIPE_SECRET_KEY\",\r\n \"STRIPE_WEBHOOK_SECRET\",\r\n \"STRIPE_IDENTITY_WEBHOOK_SECRET\",\r\n \"VOYAGE_API_KEY\",\r\n \"PERPLEXITY_API_KEY\",\r\n \"FRED_API_KEY\",\r\n \"FMP_API_KEY\",\r\n \"CURSOR_API_KEY\",\r\n] as const;\r\n\r\nconst FORBIDDEN_KEY_SET = new Set<string>(FORBIDDEN_WORKER_ENV_KEYS);\r\n\r\n/** Keys matching these suffixes are stripped (case-sensitive). */\r\nconst FORBIDDEN_SUFFIXES = [\"_SECRET\", \"_API_KEY\"] as const;\r\n\r\nexport function isForbiddenWorkerEnvKey(key: string): boolean {\r\n if (FORBIDDEN_KEY_SET.has(key)) return true;\r\n return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));\r\n}\r\n\r\nexport function listForbiddenWorkerEnvKeys(env: NodeJS.ProcessEnv): string[] {\r\n return Object.keys(env).filter(isForbiddenWorkerEnvKey).sort();\r\n}\r\n\r\nexport function scrubWorkerEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\r\n const next = { ...env };\r\n for (const key of Object.keys(next)) {\r\n if (isForbiddenWorkerEnvKey(key)) delete next[key];\r\n }\r\n return next;\r\n}\r\n\r\nexport interface WorkerEnvAudit {\r\n forbiddenPresent: string[];\r\n safe: boolean;\r\n}\r\n\r\nexport function auditWorkerEnv(env: NodeJS.ProcessEnv): WorkerEnvAudit {\r\n const forbiddenPresent = listForbiddenWorkerEnvKeys(env);\r\n return { forbiddenPresent, safe: forbiddenPresent.length === 0 };\r\n}\r\n\r\n/** @deprecated Use {@link scrubWorkerEnv} \u2014 kept for existing imports from git.ts */\r\nexport function scrubClaudeEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\r\n return scrubWorkerEnv(env);\r\n}\r\n", "import { spawnSync } from \"node:child_process\";\r\nimport { fail, hiddenSpawnOptions } from \"./util.js\";\r\n\r\nexport interface GitOptions {\r\n allowFailure?: boolean;\r\n throwError?: boolean;\r\n}\r\n\r\nexport function git(cwd: string, args: string[], options: GitOptions = {}): string {\r\n const res = spawnSync(\r\n \"git\",\r\n args,\r\n hiddenSpawnOptions({ cwd, encoding: \"utf8\" as const }),\r\n );\r\n if (res.status !== 0 && !options.allowFailure) {\r\n const message = `git ${args.join(\" \")} failed: ${res.stderr || res.stdout}`;\r\n if (options.throwError) throw new Error(message);\r\n fail(message);\r\n }\r\n return res.stdout || \"\";\r\n}\r\n\r\nexport function ensureGitRepo(repo: string): void {\r\n git(repo, [\"rev-parse\", \"--show-toplevel\"]);\r\n}\r\n\r\nexport function gitStatusShort(worktreePath: string): string[] {\r\n return git(worktreePath, [\"status\", \"--short\"], { allowFailure: true })\r\n .split(\"\\n\")\r\n .map((line) => line.trim())\r\n .filter(Boolean);\r\n}\r\n\r\nexport interface GitCaptureResult {\r\n status: number | null;\r\n stdout: string;\r\n stderr: string;\r\n error: string | null;\r\n}\r\n\r\nexport function gitCapture(cwd: string, args: string[]): GitCaptureResult {\r\n try {\r\n const res = spawnSync(\r\n \"git\",\r\n args,\r\n hiddenSpawnOptions({ cwd, encoding: \"utf8\" as const }),\r\n );\r\n return {\r\n status: res.status,\r\n stdout: res.stdout || \"\",\r\n stderr: res.stderr || \"\",\r\n error: res.error ? res.error.message : null,\r\n };\r\n } catch (error) {\r\n return {\r\n status: null,\r\n stdout: \"\",\r\n stderr: \"\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\nexport function gitIsAncestor(\r\n cwd: string,\r\n ancestor: string,\r\n descendant: string,\r\n): { isAncestor: boolean | null; error: string | null } {\r\n const res = gitCapture(cwd, [\"merge-base\", \"--is-ancestor\", ancestor, descendant]);\r\n if (res.status === 0) return { isAncestor: true, error: null };\r\n if (res.status === 1) return { isAncestor: false, error: null };\r\n return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };\r\n}\r\n\r\nexport type GitAncestryRelation = \"synced\" | \"merged\" | \"ahead\" | \"diverged\" | \"unknown\";\r\n\r\nexport interface GitAncestry {\r\n checked: boolean;\r\n base: string;\r\n head: string | null;\r\n baseHead: string | null;\r\n baseIsAncestorOfHead: boolean | null;\r\n headIsAncestorOfBase: boolean | null;\r\n relation: GitAncestryRelation;\r\n error?: string;\r\n}\r\n\r\nexport interface GitAncestryOptions {\r\n /** Branch or ref name (e.g. origin/main). Used when baseCommit is unset. */\r\n base?: string;\r\n /** Pinned SHA the worktree was created from \u2014 preferred over a moving branch ref. */\r\n baseCommit?: string;\r\n}\r\n\r\nexport function computeGitAncestry(worktreePath: string, baseOrOptions: string | GitAncestryOptions = \"origin/main\"): GitAncestry {\r\n const options: GitAncestryOptions =\r\n typeof baseOrOptions === \"string\" ? { base: baseOrOptions } : baseOrOptions;\r\n const baseLabel = options.baseCommit?.trim() || options.base?.trim() || \"origin/main\";\r\n const pinnedBaseCommit = options.baseCommit?.trim() || null;\r\n\r\n if (!worktreePath) {\r\n return unknownAncestry(baseLabel, \"missing worktree path\");\r\n }\r\n\r\n const head = gitCapture(worktreePath, [\"rev-parse\", \"HEAD\"]);\r\n if (head.status !== 0) {\r\n return unknownAncestry(baseLabel, head.error || head.stderr || head.stdout || \"failed to resolve HEAD\");\r\n }\r\n\r\n let baseSha: string;\r\n if (pinnedBaseCommit) {\r\n baseSha = pinnedBaseCommit;\r\n } else {\r\n const baseHead = gitCapture(worktreePath, [\"rev-parse\", baseLabel]);\r\n if (baseHead.status !== 0) {\r\n return unknownAncestry(\r\n baseLabel,\r\n baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${baseLabel}`,\r\n head.stdout.trim(),\r\n );\r\n }\r\n baseSha = baseHead.stdout.trim();\r\n }\r\n\r\n const headSha = head.stdout.trim();\r\n if (headSha === baseSha) {\r\n return {\r\n checked: true,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: true,\r\n headIsAncestorOfBase: true,\r\n relation: \"synced\",\r\n };\r\n }\r\n\r\n const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);\r\n const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);\r\n const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || undefined;\r\n if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {\r\n return {\r\n checked: false,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,\r\n headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,\r\n relation: \"unknown\",\r\n ...(error ? { error } : {}),\r\n };\r\n }\r\n\r\n const relation: GitAncestryRelation = baseIsAncestorOfHead.isAncestor\r\n ? \"ahead\"\r\n : headIsAncestorOfBase.isAncestor\r\n ? \"merged\"\r\n : \"diverged\";\r\n\r\n return {\r\n checked: true,\r\n base: baseLabel,\r\n head: headSha,\r\n baseHead: baseSha,\r\n baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,\r\n headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,\r\n relation,\r\n ...(error ? { error } : {}),\r\n };\r\n}\r\n\r\nfunction unknownAncestry(base: string, error: string, head: string | null = null): GitAncestry {\r\n return {\r\n checked: false,\r\n base,\r\n head,\r\n baseHead: null,\r\n baseIsAncestorOfHead: null,\r\n headIsAncestorOfBase: null,\r\n relation: \"unknown\",\r\n error,\r\n };\r\n}\r\n\r\nexport { scrubClaudeEnv, scrubWorkerEnv } from \"./worker-env.js\";\r\n", "import { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\n\r\nexport function expandHomePath(value: string): string {\r\n if (value === \"~\") return homedir();\r\n if (value.startsWith(\"~/\") || value.startsWith(\"~\\\\\")) {\r\n return path.join(homedir(), value.slice(2));\r\n }\r\n return value;\r\n}\r\n\r\nexport function resolveUserPath(value: string): string {\r\n return path.resolve(expandHomePath(value));\r\n}\r\n\r\nexport function redactHomePath(value: string): string {\r\n const expanded = expandHomePath(value);\r\n const resolved = path.resolve(expanded);\r\n const home = path.resolve(homedir());\r\n\r\n if (resolved === home) return \"~\";\r\n if (resolved.startsWith(`${home}${path.sep}`)) {\r\n return `~/${path.relative(home, resolved).split(path.sep).join(\"/\")}`;\r\n }\r\n\r\n const posix = resolved.replace(/\\\\/g, \"/\");\r\n const redacted = posix\r\n .replace(/^\\/home\\/[^/]+(?=\\/|$)/, \"~\")\r\n .replace(/^\\/Users\\/[^/]+(?=\\/|$)/, \"~\")\r\n // Windows resolves Unix-style `/home/...` paths to `C:\\home\\...`.\r\n .replace(/^[A-Za-z]:\\/home\\/[^/]+(?=\\/|$)/i, \"~\")\r\n .replace(/^[A-Za-z]:\\/Users\\/[^/]+(?=\\/|$)/i, \"~\");\r\n return redacted;\r\n}\r\n\r\n/** User-facing path strings (doctor JSON, setup output). */\r\nexport function displayUserPath(value: string): string {\r\n return redactHomePath(value);\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport { gitCapture } from \"./git.js\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\n\r\nexport type DefaultRepoDiscoverySource =\r\n | \"cwd_git\"\r\n | \"runtime_checkout\"\r\n | \"well_known_path\";\r\n\r\nexport interface DiscoveredDefaultRepo {\r\n repo: string;\r\n source: DefaultRepoDiscoverySource;\r\n}\r\n\r\nconst WELL_KNOWN_REPO_DIRS = [\r\n \"Kynver\",\r\n \"repos/Kynver\",\r\n \"repos/kynver-source-main\",\r\n \"code/Kynver\",\r\n \"projects/Kynver\",\r\n] as const;\r\n\r\nfunction readPackageName(repoRoot: string): string | null {\r\n const pkgPath = path.join(repoRoot, \"package.json\");\r\n if (!existsSync(pkgPath)) return null;\r\n try {\r\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { name?: string };\r\n return typeof pkg.name === \"string\" ? pkg.name.trim() : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function isKynverMonorepoRoot(repoRoot: string): boolean {\r\n return readPackageName(repoRoot) === \"kynver\";\r\n}\r\n\r\nexport function gitRepoRoot(startDir: string): string | null {\r\n const resolvedStart = path.resolve(startDir);\r\n if (!existsSync(resolvedStart)) return null;\r\n const probe = gitCapture(resolvedStart, [\"rev-parse\", \"--show-toplevel\"]);\r\n if (probe.status !== 0) return null;\r\n const root = probe.stdout.trim();\r\n return root.length ? path.resolve(root) : null;\r\n}\r\n\r\nfunction resolveRuntimePackageRoot(moduleUrl: string = import.meta.url): string | null {\r\n let dir = path.dirname(fileURLToPath(moduleUrl));\r\n for (let depth = 0; depth < 8; depth += 1) {\r\n const pkgPath = path.join(dir, \"package.json\");\r\n if (existsSync(pkgPath)) {\r\n try {\r\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { name?: string };\r\n if (pkg.name === \"@kynver-app/runtime\") return dir;\r\n } catch {\r\n // continue walking\r\n }\r\n }\r\n const parent = path.dirname(dir);\r\n if (parent === dir) break;\r\n dir = parent;\r\n }\r\n return null;\r\n}\r\n\r\nfunction pushCandidate(\r\n seen: Set<string>,\r\n out: DiscoveredDefaultRepo[],\r\n repo: string | null,\r\n source: DefaultRepoDiscoverySource,\r\n): void {\r\n if (!repo) return;\r\n const resolved = path.resolve(repo);\r\n if (seen.has(resolved)) return;\r\n if (!isKynverMonorepoRoot(resolved)) return;\r\n seen.add(resolved);\r\n out.push({ repo: resolved, source });\r\n}\r\n\r\nexport function discoverDefaultRepoCandidates(opts?: {\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}): DiscoveredDefaultRepo[] {\r\n const cwd = opts?.cwd ?? process.cwd();\r\n const seen = new Set<string>();\r\n const candidates: DiscoveredDefaultRepo[] = [];\r\n\r\n pushCandidate(seen, candidates, gitRepoRoot(cwd), \"cwd_git\");\r\n\r\n const runtimePkgRoot = resolveRuntimePackageRoot(opts?.runtimeModuleUrl ?? import.meta.url);\r\n if (runtimePkgRoot) {\r\n pushCandidate(seen, candidates, gitRepoRoot(runtimePkgRoot), \"runtime_checkout\");\r\n }\r\n\r\n const home = homedir();\r\n for (const rel of WELL_KNOWN_REPO_DIRS) {\r\n pushCandidate(seen, candidates, resolveUserPath(path.join(home, rel)), \"well_known_path\");\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nexport function discoverDefaultRepo(opts?: {\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}): DiscoveredDefaultRepo | null {\r\n return discoverDefaultRepoCandidates(opts)[0] ?? null;\r\n}\r\n", "import type { KynverUserConfig } from \"./config.js\";\r\n\r\nexport type WorkerPoolBoxKind = \"ghost\" | \"forge\";\r\n\r\nexport type BoxKindSource = \"config\" | \"env\" | \"default\";\r\n\r\nexport interface ResolvedBoxIdentity {\r\n boxKind: WorkerPoolBoxKind;\r\n source: BoxKindSource;\r\n /** True when identity would have been inferred from KYNVER_AGENT_OS_SLUG without an explicit box kind. */\r\n slugInferenceBlocked: boolean;\r\n warnings: string[];\r\n}\r\n\r\n/** Normalize host/box labels to ghost | forge for worker-pool attribution. */\r\nexport function normalizeWorkerPoolBoxKind(raw: string | null | undefined): WorkerPoolBoxKind {\r\n const kind = (raw ?? \"\").trim().toLowerCase();\r\n if (kind === \"ghost\" || kind === \"forge\") return kind;\r\n if (kind.includes(\"forge\")) return \"forge\";\r\n if (kind.includes(\"ghost\") || kind.includes(\"openclaw\")) return \"ghost\";\r\n return \"forge\";\r\n}\r\n\r\nfunction trimEnv(env: NodeJS.ProcessEnv, key: string): string | null {\r\n const value = env[key]?.trim();\r\n return value || null;\r\n}\r\n\r\n/**\r\n * Resolve physical box identity for capacity snapshots and daemon policy.\r\n * Never maps AgentOS workspace slug alone to box kind \u2014 Forge installs must set\r\n * `boxKind` in ~/.kynver/config.json or `KYNVER_BOX_KIND`.\r\n */\r\nexport function resolveBoxIdentity(\r\n env: NodeJS.ProcessEnv = process.env,\r\n config: Pick<KynverUserConfig, \"boxKind\"> = {},\r\n): ResolvedBoxIdentity {\r\n const warnings: string[] = [];\r\n const configKind = config.boxKind?.trim();\r\n if (configKind) {\r\n return {\r\n boxKind: normalizeWorkerPoolBoxKind(configKind),\r\n source: \"config\",\r\n slugInferenceBlocked: false,\r\n warnings,\r\n };\r\n }\r\n\r\n const envKind = trimEnv(env, \"KYNVER_BOX_KIND\");\r\n if (envKind) {\r\n return {\r\n boxKind: normalizeWorkerPoolBoxKind(envKind),\r\n source: \"env\",\r\n slugInferenceBlocked: false,\r\n warnings,\r\n };\r\n }\r\n\r\n const agentOsSlug = trimEnv(env, \"KYNVER_AGENT_OS_SLUG\");\r\n if (agentOsSlug) {\r\n warnings.push(\r\n `KYNVER_AGENT_OS_SLUG=${agentOsSlug} is a workspace slug, not box identity \u2014 set boxKind via \\`kynver setup --box-kind forge|ghost\\` or KYNVER_BOX_KIND (defaulting box kind to forge)`,\r\n );\r\n }\r\n\r\n return {\r\n boxKind: \"forge\",\r\n source: \"default\",\r\n slugInferenceBlocked: Boolean(agentOsSlug),\r\n warnings,\r\n };\r\n}\r\n\r\nexport function resolveBoxKindFromConfig(\r\n config: Pick<KynverUserConfig, \"boxKind\"> = {},\r\n env: NodeJS.ProcessEnv = process.env,\r\n): WorkerPoolBoxKind {\r\n return resolveBoxIdentity(env, config).boxKind;\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport os from \"node:os\";\r\n\r\n/**\r\n * Truly-usable memory. On Linux, prefer /proc/meminfo MemAvailable; fall back to\r\n * os.freemem() elsewhere (same semantics as resource-gate).\r\n */\r\nexport function readMemAvailableBytes(meminfoText?: string): number {\r\n if (meminfoText !== undefined) {\r\n const match = meminfoText.match(/^MemAvailable:\\s+(\\d+)\\s*kB/m);\r\n if (match) return Number(match[1]) * 1024;\r\n return os.freemem();\r\n }\r\n if (process.platform === \"linux\") {\r\n try {\r\n const meminfo = readFileSync(\"/proc/meminfo\", \"utf8\");\r\n const match = meminfo.match(/^MemAvailable:\\s+(\\d+)\\s*kB/m);\r\n if (match) return Number(match[1]) * 1024;\r\n } catch {\r\n // fall through\r\n }\r\n }\r\n return os.freemem();\r\n}\r\n", "import { existsSync, readFileSync, statfsSync } from \"node:fs\";\r\n\r\n/**\r\n * WSL host disk probe.\r\n *\r\n * Under WSL, the runtime VHDX (mounted at `/`) grows dynamically into the\r\n * Windows host C: drive. When Windows C: fills up, the VHDX cannot expand:\r\n * writes return SIGBUS, workers exit 135, and the Vmmem VM degrades while\r\n * the Linux-side `statfs /` still reports plenty of free space inside the\r\n * VHDX. This module gives the harness a cheap signal for that pressure so\r\n * it can block dispatch *before* a large npm install/build pushes Windows\r\n * C: into the ground.\r\n */\r\n\r\n/** Default warn threshold for the Windows host disk (25 GiB free). */\r\nexport const DEFAULT_WSL_HOST_WARN_FREE_BYTES = 25 * 1024 * 1024 * 1024;\r\n/** Default critical threshold for the Windows host disk (12 GiB free). Below\r\n * this, large rebuilds have been observed to trigger SIGBUS / exit 135 on\r\n * WSL when the VHDX cannot grow further. */\r\nexport const DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES = 12 * 1024 * 1024 * 1024;\r\n/** Default Windows host mount point under WSL. Overridable via env or option. */\r\nexport const DEFAULT_WSL_HOST_MOUNT = \"/mnt/c\";\r\n\r\nexport interface WslHostDiskShape {\r\n ok: boolean;\r\n /** Mount point that was probed. */\r\n path: string;\r\n freeBytes: number;\r\n totalBytes: number;\r\n usedPercent: number;\r\n warnBelowBytes: number;\r\n criticalBelowBytes: number;\r\n /** Human-readable explanation when the host disk is under pressure. */\r\n reason: string | null;\r\n /** True when the probe itself failed (mount missing, statfs error). */\r\n probeError: string | null;\r\n}\r\n\r\n/**\r\n * Cheap WSL detection. Reads `/proc/sys/kernel/osrelease` (kernel string\r\n * contains \"microsoft\" / \"WSL2\" on Microsoft's WSL kernel) and falls back\r\n * to `/proc/version`. Both reads are one-shot and gated by `existsSync`,\r\n * so non-Linux hosts return false without throwing.\r\n */\r\nexport function isWslHost(): boolean {\r\n if (process.platform !== \"linux\") return false;\r\n for (const probe of [\"/proc/sys/kernel/osrelease\", \"/proc/version\"]) {\r\n try {\r\n if (!existsSync(probe)) continue;\r\n const text = readFileSync(probe, \"utf8\");\r\n if (/microsoft|wsl/i.test(text)) return true;\r\n } catch {\r\n // ignore \u2014 try the next probe path\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nexport interface ObserveWslHostDiskOptions {\r\n /** Override the Windows host mount path (e.g. `/mnt/d`). Falls back to\r\n * `KYNVER_WSL_HOST_MOUNT` env, then `/mnt/c`. */\r\n wslHostMount?: string;\r\n wslHostFreeWarnBytes?: number;\r\n wslHostFreeCriticalBytes?: number;\r\n /** Override WSL detection for tests / cross-platform CI:\r\n * `true` \u2192 treat host as WSL; `false` \u2192 treat host as non-WSL;\r\n * `undefined` \u2192 autodetect via `isWslHost()`. */\r\n forceWsl?: boolean;\r\n /** Test seam \u2014 swap in a fake statfs. */\r\n statfs?: (path: string) => { bavail: bigint | number; blocks: bigint | number; bsize: bigint | number };\r\n}\r\n\r\n/**\r\n * Probe the Windows host disk under WSL. Returns `null` when this host is\r\n * not WSL (so callers can treat the field as optional in the gate output).\r\n * When WSL but the mount is unreachable, returns a `probeError` row with\r\n * `ok = false` rather than throwing \u2014 the gate must still block dispatch\r\n * because we can't prove the host disk is healthy.\r\n */\r\nexport function observeWslHostDisk(\r\n options: ObserveWslHostDiskOptions = {},\r\n): WslHostDiskShape | null {\r\n const wsl = options.forceWsl === undefined ? isWslHost() : options.forceWsl;\r\n if (!wsl) return null;\r\n\r\n const path =\r\n options.wslHostMount?.trim() ||\r\n process.env.KYNVER_WSL_HOST_MOUNT?.trim() ||\r\n DEFAULT_WSL_HOST_MOUNT;\r\n const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;\r\n const criticalBelowBytes =\r\n options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;\r\n\r\n const statfs = options.statfs ?? statfsSync;\r\n let stats: { bavail: bigint | number; blocks: bigint | number; bsize: bigint | number };\r\n try {\r\n stats = statfs(path);\r\n } catch (error) {\r\n return {\r\n ok: false,\r\n path,\r\n freeBytes: 0,\r\n totalBytes: 0,\r\n usedPercent: 100,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n reason: `Windows host disk probe failed at ${path}: ${(error as Error).message}`,\r\n probeError: (error as Error).message,\r\n };\r\n }\r\n\r\n const freeBytes = Number(stats.bavail) * Number(stats.bsize);\r\n const totalBytes = Number(stats.blocks) * Number(stats.bsize);\r\n const usedPercent = totalBytes > 0 ? ((totalBytes - freeBytes) / totalBytes) * 100 : 100;\r\n const lowFree = freeBytes < warnBelowBytes;\r\n const criticalFree = freeBytes < criticalBelowBytes;\r\n const ok = !lowFree && !criticalFree;\r\n\r\n const freeGiB = (freeBytes / (1024 * 1024 * 1024)).toFixed(1);\r\n let reason: string | null = null;\r\n if (!ok) {\r\n const tag = criticalFree ? \"critical\" : \"warning\";\r\n reason =\r\n `Windows host disk ${path} at ${tag}: ${freeGiB} GiB free ` +\r\n `(<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); ` +\r\n `WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;\r\n }\r\n\r\n return {\r\n ok,\r\n path,\r\n freeBytes,\r\n totalBytes,\r\n usedPercent,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n reason,\r\n probeError: null,\r\n };\r\n}\r\n\r\n/**\r\n * Short operator recovery hint embedded in gate reasons so AgentOS evidence\r\n * surfaces actionable steps without a doc lookup. Keep terse \u2014 full runbook\r\n * lives at `docs/runbooks/wsl-disk-pressure.md`.\r\n */\r\nexport function summarizeWslRecoverySteps(): string {\r\n return (\r\n \"Recovery: \" +\r\n \"1) free Windows C: (empty Recycle Bin / Storage Sense / clear %TEMP%); \" +\r\n \"2) shut down WSL (`wsl --shutdown`) then compact the VHDX (`Optimize-VHD` or `diskpart compact vdisk`); \" +\r\n \"3) clear local node_modules / .next / harness worktrees before restarting workers. \" +\r\n \"Full runbook: docs/runbooks/wsl-disk-pressure.md.\"\r\n );\r\n}\r\n", "import { statfsSync } from \"node:fs\";\r\nimport type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport {\r\n observeWslHostDisk,\r\n type ObserveWslHostDiskOptions,\r\n type WslHostDiskShape,\r\n} from \"./wsl-host.js\";\r\n\r\nconst DEFAULT_WARN_FREE_BYTES = 30 * 1024 * 1024 * 1024;\r\nconst DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;\r\nconst DEFAULT_MAX_USED_PERCENT = 80;\r\nconst DEFAULT_HARD_MAX_USED_PERCENT = 90;\r\n\r\nexport interface ObserveDiskGateInput {\r\n diskPath?: string;\r\n diskFreeWarnBytes?: number;\r\n diskFreeCriticalBytes?: number;\r\n diskMaxUsedPercent?: number;\r\n diskHardMaxUsedPercent?: number;\r\n /** Opt-out for the WSL host disk probe \u2014 leave `false`/undefined by\r\n * default so we always check `/mnt/c` under WSL. */\r\n skipWslHostCheck?: boolean;\r\n wslHost?: ObserveWslHostDiskOptions;\r\n}\r\n\r\nexport function observeRunnerDiskGate(input: ObserveDiskGateInput = {}): DispatchNextDiskGateShape {\r\n const path = input.diskPath?.trim() || \"/\";\r\n const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;\r\n const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;\r\n const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;\r\n const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;\r\n\r\n const stats = statfsSync(path);\r\n const freeBytes = Number(stats.bavail) * Number(stats.bsize);\r\n const totalBytes = Number(stats.blocks) * Number(stats.bsize);\r\n const usedPercent = totalBytes > 0 ? ((totalBytes - freeBytes) / totalBytes) * 100 : 100;\r\n const lowFree = freeBytes < warnBelowBytes;\r\n const criticalFree = freeBytes < criticalBelowBytes;\r\n const highUse = usedPercent > maxUsedPercent;\r\n const hardHighUse = usedPercent > hardMaxUsedPercent;\r\n const localOk = !lowFree && !criticalFree && !highUse && !hardHighUse;\r\n\r\n // WSL guard: the VHDX (mounted at `/`) grows into Windows C:; a healthy\r\n // local statfs is meaningless if the host disk is about to refuse writes.\r\n const wslHost: WslHostDiskShape | null = input.skipWslHostCheck\r\n ? null\r\n : observeWslHostDisk(input.wslHost);\r\n\r\n const ok = localOk && (wslHost ? wslHost.ok : true);\r\n\r\n let reason: string | null = null;\r\n if (!ok) {\r\n reason = [\r\n criticalFree ? `free space below critical ${criticalBelowBytes} bytes` : null,\r\n lowFree ? `free space below warning ${warnBelowBytes} bytes` : null,\r\n hardHighUse ? `used percent above hard cap ${hardMaxUsedPercent}%` : null,\r\n highUse ? `used percent above cap ${maxUsedPercent}%` : null,\r\n wslHost && !wslHost.ok ? wslHost.reason : null,\r\n ]\r\n .filter(Boolean)\r\n .join(\"; \");\r\n }\r\n\r\n return {\r\n ok,\r\n path,\r\n freeBytes,\r\n totalBytes,\r\n usedPercent,\r\n warnBelowBytes,\r\n criticalBelowBytes,\r\n maxUsedPercent,\r\n hardMaxUsedPercent,\r\n reason,\r\n wslHost,\r\n };\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { getHarnessPaths, harnessRunsDir, runDir as runDirPath } from \"./paths.js\";\r\nimport { readJson, safeSlug, writeJson } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport interface HarnessRunRecord {\r\n id: string;\r\n name: string;\r\n repo: string;\r\n base: string;\r\n baseCommit: string;\r\n status: string;\r\n createdAt: string;\r\n workers: Record<string, { workerDir: string; statusPath: string }>;\r\n}\r\n\r\nexport function getPaths() {\r\n return getHarnessPaths();\r\n}\r\n\r\nexport function loadRun(id: string): HarnessRunRecord {\r\n const { runsDir } = getPaths();\r\n return readJson<HarnessRunRecord>(path.join(runDirPath(runsDir, safeSlug(id)), \"run.json\"));\r\n}\r\n\r\n/**\r\n * Load every run record on disk. Used for global, cross-run accounting (the\r\n * resource gate must see workers from ALL runs, and stale-run finalization\r\n * iterates the whole set). Unreadable/partial run dirs are skipped.\r\n */\r\nexport function listRunRecords(): HarnessRunRecord[] {\r\n const { runsDir } = getPaths();\r\n return listRunRecordsAt(runsDir);\r\n}\r\n\r\nexport function listRunRecordsForHarnessRoot(harnessRoot: string): HarnessRunRecord[] {\r\n return listRunRecordsAt(harnessRunsDir(harnessRoot));\r\n}\r\n\r\nfunction isRunDirectoryEntry(runDirPath: string): boolean {\r\n try {\r\n return statSync(runDirPath).isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction listRunRecordsAt(runsDir: string): HarnessRunRecord[] {\r\n if (!existsSync(runsDir)) return [];\r\n const runs: HarnessRunRecord[] = [];\r\n for (const entry of readdirSync(runsDir, { withFileTypes: true })) {\r\n if (entry.name === \"runs\") continue;\r\n const runDir = path.join(runsDir, entry.name);\r\n if (!isRunDirectoryEntry(runDir)) continue;\r\n const run = readJson<HarnessRunRecord | undefined>(\r\n path.join(runDir, \"run.json\"),\r\n undefined,\r\n );\r\n if (run?.id) runs.push(run);\r\n }\r\n return runs;\r\n}\r\n\r\nexport function loadWorker(runId: string, name: string): HarnessWorkerRecord {\r\n const { runsDir } = getPaths();\r\n return readJson<HarnessWorkerRecord>(\r\n path.join(runDirPath(runsDir, safeSlug(runId)), \"workers\", safeSlug(name), \"worker.json\"),\r\n );\r\n}\r\n\r\nexport function saveRun(run: HarnessRunRecord): void {\r\n const { runsDir } = getPaths();\r\n writeJson(path.join(runDirPath(runsDir, run.id), \"run.json\"), run);\r\n}\r\n\r\nexport function saveWorker(runId: string, worker: HarnessWorkerRecord): void {\r\n const { runsDir } = getPaths();\r\n writeJson(path.join(runDirPath(runsDir, runId), \"workers\", worker.name, \"worker.json\"), worker);\r\n}\r\n\r\nexport function runDirectory(id: string): string {\r\n const { harnessRoot } = getPaths();\r\n return runDirectoryAt(harnessRoot, id);\r\n}\r\n\r\nexport function runDirectoryAt(harnessRoot: string, id: string): string {\r\n return runDirPath(harnessRunsDir(harnessRoot), safeSlug(id));\r\n}\r\n", "import { existsSync, readdirSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { runDirectory, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\n/**\r\n * Union of `run.json` worker keys and on-disk worker dirs for one run.\r\n *\r\n * Watchdog replenishment can spawn workers whose `worker.json` exists before\r\n * `run.json` is updated (or when concurrent spawns lose a last-write-wins race).\r\n * Finalization, capacity gates, and operator rollups must not treat those\r\n * live workers as absent.\r\n */\r\nexport function listRunWorkerNames(run: HarnessRunRecord): string[] {\r\n const names = new Set<string>();\r\n for (const name of Object.keys(run.workers || {})) {\r\n names.add(safeSlug(name));\r\n }\r\n const workersDir = path.join(runDirectory(run.id), \"workers\");\r\n if (!existsSync(workersDir)) return [...names];\r\n for (const entry of readdirSync(workersDir, { withFileTypes: true })) {\r\n if (!entry.isDirectory()) continue;\r\n names.add(safeSlug(entry.name));\r\n }\r\n return [...names];\r\n}\r\n", "// Resolve structured harness finalResult from a terminal heartbeat line.\r\n\r\nfunction tryParseJsonObject(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed.startsWith(\"{\")) return null;\r\n try {\r\n const parsed: unknown = JSON.parse(trimmed);\r\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction embeddedRecordFromProse(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed) return null;\r\n const direct = tryParseJsonObject(trimmed);\r\n if (direct) return direct;\r\n\r\n const candidates: Record<string, unknown>[] = [];\r\n const fenceRe = /```(?:json)?\\s*([\\s\\S]*?)```/gi;\r\n let fenceMatch: RegExpExecArray | null;\r\n while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {\r\n const fromFence = tryParseJsonObject(fenceMatch[1] ?? \"\");\r\n if (fromFence) candidates.push(fromFence);\r\n }\r\n\r\n const firstBrace = trimmed.indexOf(\"{\");\r\n const lastBrace = trimmed.lastIndexOf(\"}\");\r\n if (firstBrace >= 0 && lastBrace > firstBrace) {\r\n const slice = tryParseJsonObject(trimmed.slice(firstBrace, lastBrace + 1));\r\n if (slice) candidates.push(slice);\r\n }\r\n\r\n return candidates.length > 0 ? candidates[candidates.length - 1]! : null;\r\n}\r\n\r\n/**\r\n * Prefer an explicit heartbeat `finalResult`, else structured JSON embedded in\r\n * `summary`, else the summary string (legacy contract).\r\n */\r\nexport function terminalFinalResultFromHeartbeatRow(\r\n row: Record<string, unknown>,\r\n): unknown {\r\n const explicit = row.finalResult ?? row.final_result;\r\n if (explicit !== undefined && explicit !== null) {\r\n if (typeof explicit === \"string\") {\r\n const embedded = embeddedRecordFromProse(explicit);\r\n return embedded ?? (explicit.trim() || null);\r\n }\r\n return explicit;\r\n }\r\n\r\n const summary = typeof row.summary === \"string\" ? row.summary.trim() : \"\";\r\n if (!summary) return null;\r\n\r\n const embedded = embeddedRecordFromProse(summary);\r\n if (embedded) return embedded;\r\n\r\n return summary;\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport { terminalFinalResultFromHeartbeatRow } from \"./heartbeat-final-result.js\";\r\nimport { safeJson } from \"./util.js\";\r\nimport type { RuntimeBoxResourceSnapshot, RuntimeBoxResourceSnapshotPrEvidence } from \"./box-resource-snapshot.js\";\r\n\r\nexport interface ParsedHeartbeat {\r\n heartbeatCount: number;\r\n lastHeartbeatAt: string | null;\r\n lastHeartbeatPhase: string | null;\r\n lastHeartbeatSummary: string | null;\r\n /** Structured finalResult from the terminal `phase: complete` heartbeat line. */\r\n terminalFinalResult: unknown;\r\n heartbeatBlocker: string | null;\r\n timestampAnomalies: ParsedHeartbeatTimestampAnomaly[];\r\n lastBoxResourceSnapshot: RuntimeBoxResourceSnapshot | null;\r\n lastPrEvidence: RuntimeBoxResourceSnapshotPrEvidence[];\r\n}\r\n\r\nexport interface ParsedHeartbeatTimestampAnomaly {\r\n kind: \"future_heartbeat_timestamp\";\r\n observedAt: string;\r\n clampedTo: string;\r\n}\r\n\r\nconst HEARTBEAT_FUTURE_SKEW_MS = 60_000;\r\n\r\n/** Worker contract: append `phase: \"complete\"` when productively finished. */\r\nexport function isTerminalHeartbeatPhase(phase: string | null | undefined): boolean {\r\n return phase === \"complete\";\r\n}\r\n\r\n/**\r\n * When stdout has no stream-json `result` yet (common for Cursor workers mid-exit),\r\n * treat the worker's completion heartbeat as a synthetic final result so lifecycle\r\n * sync, completion replay, and resource gates advance.\r\n */\r\nexport function terminalFinalResultFromHeartbeat(heartbeat: ParsedHeartbeat): unknown {\r\n if (!isTerminalHeartbeatPhase(heartbeat.lastHeartbeatPhase)) return null;\r\n if (heartbeat.terminalFinalResult !== undefined && heartbeat.terminalFinalResult !== null) {\r\n return heartbeat.terminalFinalResult;\r\n }\r\n const summary = heartbeat.lastHeartbeatSummary?.trim();\r\n return summary || \"completed\";\r\n}\r\n\r\nexport function parseHeartbeat(file: string): ParsedHeartbeat {\r\n const result: ParsedHeartbeat = {\r\n heartbeatCount: 0,\r\n lastHeartbeatAt: null,\r\n lastHeartbeatPhase: null,\r\n lastHeartbeatSummary: null,\r\n terminalFinalResult: null,\r\n heartbeatBlocker: null,\r\n timestampAnomalies: [],\r\n lastBoxResourceSnapshot: null,\r\n lastPrEvidence: [],\r\n };\r\n if (!existsSync(file)) return result;\r\n const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;\r\n const clampedTo = new Date(maxFutureMs).toISOString();\r\n const lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\r\n for (const line of lines) {\r\n const entry = safeJson(line);\r\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) continue;\r\n const row = entry as Record<string, unknown>;\r\n result.heartbeatCount++;\r\n if (row.ts) {\r\n const ts = String(row.ts);\r\n const tsMs = Date.parse(ts);\r\n if (Number.isFinite(tsMs) && tsMs > maxFutureMs) {\r\n result.timestampAnomalies.push({\r\n kind: \"future_heartbeat_timestamp\",\r\n observedAt: ts,\r\n clampedTo,\r\n });\r\n } else {\r\n result.lastHeartbeatAt = ts;\r\n }\r\n }\r\n if (row.phase !== undefined && row.phase !== null) result.lastHeartbeatPhase = String(row.phase);\r\n if (row.summary !== undefined && row.summary !== null) result.lastHeartbeatSummary = String(row.summary);\r\n if (isTerminalHeartbeatPhase(result.lastHeartbeatPhase)) {\r\n result.terminalFinalResult = terminalFinalResultFromHeartbeatRow(row);\r\n }\r\n result.heartbeatBlocker = row.blocker ? String(row.blocker) : null;\r\n if (row.boxResourceSnapshot && typeof row.boxResourceSnapshot === \"object\" && !Array.isArray(row.boxResourceSnapshot)) {\r\n result.lastBoxResourceSnapshot = row.boxResourceSnapshot as RuntimeBoxResourceSnapshot;\r\n }\r\n if (Array.isArray(row.prEvidence)) {\r\n result.lastPrEvidence = row.prEvidence.filter(\r\n (entry): entry is RuntimeBoxResourceSnapshotPrEvidence =>\r\n !!entry &&\r\n typeof entry === \"object\" &&\r\n typeof (entry as RuntimeBoxResourceSnapshotPrEvidence).prUrl === \"string\",\r\n );\r\n }\r\n }\r\n return result;\r\n}\r\n", "/**\r\n * Normalize and classify repo text-search commands for harness operators and chat agents.\r\n *\r\n * Codex/OpenClaw often emit `search \"pattern\" in <scope>` meta that maps poorly to ripgrep\r\n * (e.g. `in !node_modules` instead of `-g '!node_modules/**'`, or `in package.json` as a path).\r\n */\r\n\r\nconst RG_BINARIES = new Set([\"rg\", \"ripgrep\", \"grep\"]);\r\nconst RG_OPTS_WITH_VALUE = new Set([\r\n \"-e\",\r\n \"--regexp\",\r\n \"-f\",\r\n \"--file\",\r\n \"-m\",\r\n \"--max-count\",\r\n \"-A\",\r\n \"--after-context\",\r\n \"-B\",\r\n \"--before-context\",\r\n \"-C\",\r\n \"--context\",\r\n \"-g\",\r\n \"--glob\",\r\n \"--iglob\",\r\n]);\r\n\r\nexport type RepoSearchKind =\r\n | \"not_repo_search\"\r\n | \"bad_scope\"\r\n | \"rg_exclude_syntax\"\r\n | \"no_matches\";\r\n\r\nexport interface RepoSearchContext {\r\n kind: RepoSearchKind;\r\n pattern?: string;\r\n target?: string;\r\n}\r\n\r\nfunction binaryName(token: string | undefined): string | null {\r\n if (!token) return null;\r\n const base = token.split(\"/\").pop() ?? token;\r\n return base.replace(/\\.exe$/i, \"\").toLowerCase();\r\n}\r\n\r\nfunction splitShellWords(input: string): string[] {\r\n if (!input) return [];\r\n const words: string[] = [];\r\n let current = \"\";\r\n let quote: string | undefined;\r\n let escaped = false;\r\n for (const char of input) {\r\n if (escaped) {\r\n current += char;\r\n escaped = false;\r\n continue;\r\n }\r\n if (char === \"\\\\\") {\r\n escaped = true;\r\n continue;\r\n }\r\n if (quote) {\r\n if (char === quote) quote = undefined;\r\n else current += char;\r\n continue;\r\n }\r\n if (char === '\"' || char === \"'\") {\r\n quote = char;\r\n continue;\r\n }\r\n if (/\\s/.test(char)) {\r\n if (current) {\r\n words.push(current);\r\n current = \"\";\r\n }\r\n continue;\r\n }\r\n current += char;\r\n }\r\n if (current) words.push(current);\r\n return words;\r\n}\r\n\r\nfunction isRgArgv(argv: string[]): boolean {\r\n const bin = binaryName(argv[0]);\r\n return Boolean(bin && RG_BINARIES.has(bin));\r\n}\r\n\r\nexport function isSingleFileSearchTarget(target: string | undefined): boolean {\r\n if (!target || target.includes(\"/\") || target.includes(\"*\")) return false;\r\n return /\\.(?:json|md|mjs|cjs|js|ts|tsx|yaml|yml)$/iu.test(target);\r\n}\r\n\r\n/** `!node_modules` as a path is invalid \u2014 ripgrep needs `-g '!node_modules/**'`. */\r\nexport function isRgExcludeScopeTarget(target: string | undefined): boolean {\r\n if (!target) return false;\r\n const t = target.trim();\r\n return t.startsWith(\"!\") && !t.includes(\"/\") && !t.endsWith(\"/**\");\r\n}\r\n\r\nfunction fixRgGlobToken(token: string): string {\r\n if (!token.startsWith(\"--glob=\")) return token;\r\n const value = token.slice(\"--glob=\".length);\r\n if (value.startsWith(\"!\") && !value.includes(\"/\") && !value.endsWith(\"/**\")) {\r\n return `--glob=${value}/**`;\r\n }\r\n return token;\r\n}\r\n\r\nfunction collectRgPositional(argv: string[]): string[] {\r\n const positional: string[] = [];\r\n for (let i = 1; i < argv.length; i += 1) {\r\n const token = argv[i];\r\n if (!token) continue;\r\n if (token === \"--\") {\r\n positional.push(...argv.slice(i + 1));\r\n break;\r\n }\r\n if (token.startsWith(\"-\")) {\r\n if (token.includes(\"=\")) continue;\r\n if (RG_OPTS_WITH_VALUE.has(token)) i += 1;\r\n continue;\r\n }\r\n positional.push(token);\r\n }\r\n return positional;\r\n}\r\n\r\nexport function normalizeRgArgv(argv: string[]): { argv: string[]; changed: boolean } {\r\n let changed = false;\r\n const out = argv.map((token) => {\r\n const fixed = fixRgGlobToken(token);\r\n if (fixed !== token) changed = true;\r\n return fixed;\r\n });\r\n const positional = collectRgPositional(out);\r\n if (positional.length === 2) {\r\n const [pattern, target] = positional;\r\n if (isSingleFileSearchTarget(target)) {\r\n return { argv: [out[0] ?? \"rg\", \"-g\", target, pattern, \".\"], changed: true };\r\n }\r\n }\r\n return { argv: out, changed };\r\n}\r\n\r\nexport function normalizeRepoSearchCommand(command: string): { command: string; changed: boolean } {\r\n const trimmed = command.trim();\r\n if (!trimmed) return { command: trimmed, changed: false };\r\n const joiner = trimmed.includes(\"&&\") ? \" && \" : trimmed.includes(\"||\") ? \" || \" : \"; \";\r\n const stages = trimmed.split(/\\s*(?:&&|\\|\\||;)\\s*/u);\r\n let changed = false;\r\n const normalizedStages = stages.map((stage) => {\r\n const argv = splitShellWords(stage.trim());\r\n if (!argv.length || !isRgArgv(argv)) return stage;\r\n const normalized = normalizeRgArgv(argv);\r\n if (normalized.changed) {\r\n changed = true;\r\n return normalized.argv.join(\" \");\r\n }\r\n return stage;\r\n });\r\n if (!changed) return { command: trimmed, changed: false };\r\n return { command: normalizedStages.join(joiner), changed: true };\r\n}\r\n\r\nexport function extractSearchMeta(meta: string): { pattern?: string; target?: string } {\r\n if (!meta) return {};\r\n const pipelineMatch = meta.match(/search\\s+\"(.+)\"\\s+in\\s+([^()]+?)(?:\\s*\\(|$)/iu);\r\n if (pipelineMatch) {\r\n return { pattern: pipelineMatch[1], target: pipelineMatch[2]?.trim() };\r\n }\r\n const match = meta.match(/^search\\s+\"(.+)\"\\s+in\\s+(.+)$/iu);\r\n if (!match) return {};\r\n return { pattern: match[1], target: match[2]?.trim() };\r\n}\r\n\r\nexport function classifyRepoSearchMeta(meta: string): RepoSearchContext {\r\n const { pattern, target } = extractSearchMeta(meta);\r\n if (!pattern) return { kind: \"not_repo_search\" };\r\n if (isRgExcludeScopeTarget(target)) {\r\n return { kind: \"rg_exclude_syntax\", pattern, target };\r\n }\r\n if (isSingleFileSearchTarget(target)) {\r\n return { kind: \"bad_scope\", pattern, target };\r\n }\r\n return { kind: \"not_repo_search\", pattern, target };\r\n}\r\n\r\nexport function metaToNormalizedRgCommand(meta: string): { command: string; changed: boolean } | null {\r\n const { pattern, target } = extractSearchMeta(meta);\r\n if (!pattern) return null;\r\n if (isRgExcludeScopeTarget(target)) {\r\n const glob = `${target!.trim()}/**`;\r\n return {\r\n command: `rg \"${pattern}\" -g '${glob}' .`,\r\n changed: true,\r\n };\r\n }\r\n if (target && isSingleFileSearchTarget(target)) {\r\n return {\r\n command: `rg -g ${target} \"${pattern}\" .`,\r\n changed: true,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nexport function formatRepoSearchGuidance(ctx: RepoSearchContext): string | null {\r\n if (\r\n ctx.kind === \"bad_scope\" &&\r\n ctx.pattern?.includes(\"agent-os-land-pr\") &&\r\n ctx.target === \"package.json\"\r\n ) {\r\n return (\r\n \"Search package.json with a glob from the repo root: \" +\r\n \"`rg -g package.json agent-os-land-pr .` \u2014 or run `node scripts/agent-os-land-pr.mjs <pr-url>` directly.\"\r\n );\r\n }\r\n if (ctx.kind === \"bad_scope\" && ctx.pattern && ctx.target) {\r\n return `Use \\`rg -g '${ctx.target}' ${ctx.pattern} .\\` from the repo root instead of treating ${ctx.target} as a folder.`;\r\n }\r\n if (ctx.kind === \"rg_exclude_syntax\" && ctx.pattern) {\r\n const glob = ctx.target ? `${ctx.target.trim()}/**` : \"!node_modules/**\";\r\n return (\r\n `Repo search scope \\`${ctx.target ?? \"!node_modules\"}\\` is not a valid ripgrep path. ` +\r\n `Use \\`rg \"${ctx.pattern}\" -g '${glob}' .\\` from the repo root (exclude globs need a \\`/**\\` suffix).`\r\n );\r\n }\r\n if (ctx.kind === \"no_matches\" && ctx.pattern) {\r\n return `No matches for \"${ctx.pattern}\". Try a broader pattern, drop overly short tokens, or search from the repo root with \\`rg \"${ctx.pattern}\" .\\`.`;\r\n }\r\n return null;\r\n}\r\n\r\n/** Extract `search \"\u2026\" in \u2026` from a tool-failure line or command string. */\r\nexport function extractSearchMetaFromToolLine(line: string): string | null {\r\n const match = line.match(/search\\s+\"(.+)\"\\s+in\\s+([^()]+?)(?:\\s*\\(agent\\)|\\s*failed|$)/iu);\r\n if (!match) return null;\r\n return `search \"${match[1]}\" in ${match[2]?.trim()}`;\r\n}\r\n\r\nexport function diagnoseRepoSearchFailure(input: {\r\n meta?: string;\r\n command?: string;\r\n exitCode?: number;\r\n}): string | null {\r\n const meta =\r\n input.meta?.trim() ||\r\n (input.command ? extractSearchMetaFromToolLine(input.command) : null) ||\r\n null;\r\n if (meta) {\r\n const ctx = classifyRepoSearchMeta(meta);\r\n const guidance = formatRepoSearchGuidance(ctx);\r\n if (guidance) return guidance;\r\n const normalized = metaToNormalizedRgCommand(meta);\r\n if (normalized?.changed) {\r\n return `Repo search used an invalid scope. Retry with: \\`${normalized.command}\\`.`;\r\n }\r\n }\r\n if (input.command && /\\b(rg|ripgrep)\\b/i.test(input.command)) {\r\n const normalized = normalizeRepoSearchCommand(input.command);\r\n if (normalized.changed) {\r\n return `Ripgrep scope may be invalid. Retry with: \\`${normalized.command}\\`.`;\r\n }\r\n if (input.exitCode === 1) {\r\n return \"Ripgrep returned no matches (exit 1). Try a broader pattern or search from the repo root.\";\r\n }\r\n }\r\n return null;\r\n}\r\n", "// Classify harness shell tool results for operator-facing streams (tail, status, Telegram).\r\n//\r\n// npm audit exits 1 when advisories exist \u2014 that is a successful run with findings,\r\n// not a command execution failure. ripgrep exits 1 when there are no matches \u2014 also\r\n// not a command execution failure. Reserve \"command failed\" for ENOLOCK, network\r\n// errors, invalid JSON, and other tool failures.\r\n\r\nimport { diagnoseRepoSearchFailure, normalizeRepoSearchCommand } from \"./repo-search.js\";\r\n\r\nexport type ShellCommandOutcomeKind =\r\n | \"success\"\r\n | \"audit_findings\"\r\n | \"search_no_matches\"\r\n | \"command_failure\";\r\n\r\nexport interface NpmAuditSummary {\r\n total: number;\r\n critical: number;\r\n high: number;\r\n moderate: number;\r\n low: number;\r\n info: number;\r\n}\r\n\r\nexport interface ShellCommandOutcome {\r\n kind: ShellCommandOutcomeKind;\r\n exitCode: number;\r\n /** Short operator-facing line (no raw JSON blob). */\r\n summary: string;\r\n /** Present when kind === audit_findings and JSON parsed. */\r\n audit?: NpmAuditSummary;\r\n /** When JSON was expected but invalid. */\r\n parseError?: string;\r\n}\r\n\r\nconst NPM_AUDIT_RE = /\\bnpm\\s+audit\\b/i;\r\nconst RG_CMD_RE = /\\b(rg|ripgrep)\\b/i;\r\nconst RG_REAL_ERROR_RE = /\\b(error|invalid|unknown|panic|not found)\\b/i;\r\n\r\nfunction tidy(text: string, max = 200): string {\r\n const one = text.replace(/\\s+/g, \" \").trim();\r\n return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;\r\n}\r\n\r\nfunction extractJsonObject(text: string): unknown | null {\r\n const trimmed = text.trim();\r\n if (!trimmed) return null;\r\n if (trimmed.startsWith(\"{\")) {\r\n try {\r\n return JSON.parse(trimmed);\r\n } catch {\r\n /* fall through \u2014 scan for embedded object */\r\n }\r\n }\r\n const start = trimmed.indexOf(\"{\");\r\n const end = trimmed.lastIndexOf(\"}\");\r\n if (start >= 0 && end > start) {\r\n try {\r\n return JSON.parse(trimmed.slice(start, end + 1));\r\n } catch {\r\n return null;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\r\n}\r\n\r\nexport function summarizeNpmAuditReport(report: Record<string, unknown>): NpmAuditSummary | null {\r\n const meta = report.metadata;\r\n if (!isRecord(meta)) return null;\r\n const vuln = meta.vulnerabilities;\r\n if (!isRecord(vuln)) return null;\r\n const num = (key: string) => (typeof vuln[key] === \"number\" ? vuln[key] : 0);\r\n const summary: NpmAuditSummary = {\r\n info: num(\"info\"),\r\n low: num(\"low\"),\r\n moderate: num(\"moderate\"),\r\n high: num(\"high\"),\r\n critical: num(\"critical\"),\r\n total: num(\"total\"),\r\n };\r\n if (\r\n typeof vuln.total !== \"number\" &&\r\n !summary.critical &&\r\n !summary.high &&\r\n !summary.moderate &&\r\n !summary.low &&\r\n !summary.info\r\n ) {\r\n return null;\r\n }\r\n return summary;\r\n}\r\n\r\nfunction formatAuditSummaryLine(audit: NpmAuditSummary): string {\r\n const parts: string[] = [];\r\n if (audit.critical) parts.push(`${audit.critical} critical`);\r\n if (audit.high) parts.push(`${audit.high} high`);\r\n if (audit.moderate) parts.push(`${audit.moderate} moderate`);\r\n if (audit.low) parts.push(`${audit.low} low`);\r\n if (audit.info) parts.push(`${audit.info} info`);\r\n const breakdown = parts.length ? parts.join(\", \") : \"see report\";\r\n return `npm audit: ${audit.total} vulnerabilit${audit.total === 1 ? \"y\" : \"ies\"} (${breakdown}) \u2014 remediation required`;\r\n}\r\n\r\nfunction npmAuditFailureReason(report: Record<string, unknown>, stderr: string): string {\r\n const err = report.error;\r\n if (isRecord(err)) {\r\n const summary = typeof err.summary === \"string\" ? err.summary.trim() : \"\";\r\n const code = typeof err.code === \"string\" ? err.code.trim() : \"\";\r\n if (summary) return code ? `${code}: ${summary}` : summary;\r\n if (code) return code;\r\n }\r\n const detail = typeof report.message === \"string\" ? report.message.trim() : \"\";\r\n if (detail) return detail;\r\n const errTail = stderr.trim();\r\n if (errTail) return tidy(errTail.split(\"\\n\").find(Boolean) ?? errTail, 160);\r\n return \"npm audit failed\";\r\n}\r\n\r\nexport function classifyNpmAuditOutcome(input: {\r\n exitCode: number;\r\n stdout: string;\r\n stderr: string;\r\n}): ShellCommandOutcome {\r\n const combined = `${input.stdout}\\n${input.stderr}`.trim();\r\n const parsed = extractJsonObject(combined);\r\n\r\n if (!parsed || !isRecord(parsed)) {\r\n const tail = tidy(combined || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `npm audit failed (invalid or missing JSON): ${tail}`,\r\n parseError: \"invalid_json\",\r\n };\r\n }\r\n\r\n if (isRecord(parsed.error)) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `npm audit command failed: ${npmAuditFailureReason(parsed, input.stderr)}`,\r\n };\r\n }\r\n\r\n const audit = summarizeNpmAuditReport(parsed);\r\n if (!audit) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: \"npm audit failed: JSON response missing vulnerability metadata\",\r\n parseError: \"missing_metadata\",\r\n };\r\n }\r\n\r\n if (input.exitCode === 0 && audit.total === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: \"npm audit: no vulnerabilities reported\",\r\n audit,\r\n };\r\n }\r\n\r\n return {\r\n kind: \"audit_findings\",\r\n exitCode: input.exitCode,\r\n summary: formatAuditSummaryLine(audit),\r\n audit,\r\n };\r\n}\r\n\r\nfunction isNpmAuditCommand(command: string): boolean {\r\n return NPM_AUDIT_RE.test(command);\r\n}\r\n\r\nfunction isRgCommand(command: string): boolean {\r\n return RG_CMD_RE.test(command);\r\n}\r\n\r\nfunction classifyRgOutcome(input: {\r\n command: string;\r\n exitCode: number;\r\n stdout: string;\r\n stderr: string;\r\n interleaved: string;\r\n}): ShellCommandOutcome {\r\n const diagnosis = diagnoseRepoSearchFailure({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n });\r\n\r\n if (input.exitCode === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: \"ripgrep finished (exit 0)\",\r\n };\r\n }\r\n\r\n if (input.exitCode === 1) {\r\n const errText = (input.stderr || input.interleaved).trim();\r\n if (errText && RG_REAL_ERROR_RE.test(errText)) {\r\n const tail = tidy(errText, 160);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: 1,\r\n summary: diagnosis ?? `ripgrep failed (exit 1): ${tail}`,\r\n };\r\n }\r\n const normalized = normalizeRepoSearchCommand(input.command);\r\n const retry =\r\n normalized.changed && !diagnosis ? ` Retry with: \\`${normalized.command}\\`.` : \"\";\r\n return {\r\n kind: \"search_no_matches\",\r\n exitCode: 1,\r\n summary:\r\n diagnosis ??\r\n `ripgrep: no matches (exit 1).${retry} Try a broader pattern or search from the repo root.`,\r\n };\r\n }\r\n\r\n const tail = tidy(input.interleaved || input.stdout || input.stderr || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: diagnosis ?? `ripgrep failed (exit ${input.exitCode}): ${tail}`,\r\n };\r\n}\r\n\r\nexport function classifyShellCommandOutcome(input: {\r\n command: string;\r\n exitCode: number;\r\n stdout?: string;\r\n stderr?: string;\r\n interleavedOutput?: string;\r\n}): ShellCommandOutcome {\r\n const stdout = input.stdout ?? \"\";\r\n const stderr = input.stderr ?? \"\";\r\n const interleaved = input.interleavedOutput ?? \"\";\r\n\r\n if (isNpmAuditCommand(input.command)) {\r\n const body = stdout.trim() || interleaved.trim() || stderr.trim();\r\n return classifyNpmAuditOutcome({\r\n exitCode: input.exitCode,\r\n stdout: body,\r\n stderr,\r\n });\r\n }\r\n\r\n if (isRgCommand(input.command)) {\r\n return classifyRgOutcome({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n stdout,\r\n stderr,\r\n interleaved,\r\n });\r\n }\r\n\r\n const searchDiagnosis = diagnoseRepoSearchFailure({\r\n command: input.command,\r\n exitCode: input.exitCode,\r\n });\r\n if (searchDiagnosis && input.exitCode !== 0) {\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: searchDiagnosis,\r\n };\r\n }\r\n\r\n if (input.exitCode === 0) {\r\n return {\r\n kind: \"success\",\r\n exitCode: 0,\r\n summary: `command succeeded (exit 0)`,\r\n };\r\n }\r\n\r\n const tail = tidy(interleaved || stdout || stderr || `exit ${input.exitCode}`, 180);\r\n return {\r\n kind: \"command_failure\",\r\n exitCode: input.exitCode,\r\n summary: `command failed (exit ${input.exitCode}): ${tail}`,\r\n };\r\n}\r\n", "import { existsSync, readFileSync } from \"node:fs\";\r\nimport {\r\n classifyShellCommandOutcome,\r\n type ShellCommandOutcome,\r\n} from \"./shell-command-outcome.js\";\r\nimport { oneLine, safeJson } from \"./util.js\";\r\n\r\nexport interface ParsedStream {\r\n firstEventAt: string | null;\r\n lastEventAt: string | null;\r\n currentTool: string | null;\r\n finalResult: unknown;\r\n error: string | null;\r\n /** Most recent non-success shell outcome for operator error streams. */\r\n lastShellOutcome: ShellCommandOutcome | null;\r\n}\r\n\r\nfunction eventTimestampIso(event: Record<string, unknown>): string | undefined {\r\n const tsMs = event.timestamp_ms as number | undefined;\r\n return (event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : undefined)) as\r\n | string\r\n | undefined;\r\n}\r\n\r\n/** Cursor `stream-json` encodes tools as `{ grepToolCall: \u2026 }` keys on `tool_call`. */\r\nfunction cursorToolNameFromCall(toolCall: Record<string, unknown> | undefined): string | null {\r\n if (!toolCall) return null;\r\n for (const key of Object.keys(toolCall)) {\r\n if (key.endsWith(\"ToolCall\")) {\r\n const stem = key.slice(0, -\"ToolCall\".length);\r\n return stem.length ? stem : key;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction recordStreamResult(result: ParsedStream, event: Record<string, unknown>): void {\r\n result.finalResult = event.result || event.subtype || event.terminal_reason || \"completed\";\r\n if (event.is_error) {\r\n result.error = String(event.result || event.api_error_status || \"stream result error\");\r\n }\r\n}\r\n\r\nfunction shellPayloadFromCursorEvent(\r\n event: Record<string, unknown>,\r\n): { command: string; exitCode: number; stdout: string; stderr: string; interleaved: string } | null {\r\n if (event.type !== \"tool_call\" || event.subtype !== \"completed\") return null;\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : null;\r\n const shell = toolCall?.shellToolCall;\r\n if (!shell || typeof shell !== \"object\" || Array.isArray(shell)) return null;\r\n const shellObj = shell as Record<string, unknown>;\r\n const args = shellObj.args;\r\n const command =\r\n args && typeof args === \"object\" && !Array.isArray(args) && typeof (args as Record<string, unknown>).command === \"string\"\r\n ? String((args as Record<string, unknown>).command)\r\n : \"\";\r\n const result = shellObj.result;\r\n if (!result || typeof result !== \"object\" || Array.isArray(result)) return null;\r\n const body = (result as Record<string, unknown>).success ?? (result as Record<string, unknown>).failure;\r\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return null;\r\n const row = body as Record<string, unknown>;\r\n const exitCode = typeof row.exitCode === \"number\" ? row.exitCode : 0;\r\n return {\r\n command,\r\n exitCode,\r\n stdout: typeof row.stdout === \"string\" ? row.stdout : \"\",\r\n stderr: typeof row.stderr === \"string\" ? row.stderr : \"\",\r\n interleaved: typeof row.interleavedOutput === \"string\" ? row.interleavedOutput : \"\",\r\n };\r\n}\r\n\r\nfunction applyShellOutcome(parsed: ParsedStream, outcome: ShellCommandOutcome): void {\r\n if (outcome.kind === \"success\" || outcome.kind === \"search_no_matches\") return;\r\n parsed.lastShellOutcome = outcome;\r\n}\r\n\r\n/**\r\n * Parse harness worker stdout (`stream-json` from Claude Code or Cursor Agent).\r\n * Cursor emits `tool_call` events and may only write `type: \"result\"` after exit;\r\n * completion heartbeats are merged in `computeWorkerStatus`.\r\n */\r\nexport function parseHarnessStream(file: string): ParsedStream {\r\n const result: ParsedStream = {\r\n firstEventAt: null,\r\n lastEventAt: null,\r\n currentTool: null,\r\n finalResult: null,\r\n error: null,\r\n lastShellOutcome: null,\r\n };\r\n if (!existsSync(file)) return result;\r\n const lines = readFileSync(file, \"utf8\").split(\"\\n\").filter(Boolean);\r\n for (const line of lines) {\r\n const event = safeJson(line) as Record<string, unknown> | null;\r\n if (!event) continue;\r\n const ts = eventTimestampIso(event);\r\n if (ts) {\r\n result.firstEventAt ||= ts;\r\n result.lastEventAt = ts;\r\n }\r\n if (\r\n event.type === \"stream_event\" &&\r\n event.event &&\r\n typeof event.event === \"object\" &&\r\n (event.event as Record<string, unknown>).type === \"content_block_start\"\r\n ) {\r\n const block = (event.event as Record<string, unknown>).content_block as Record<string, unknown> | undefined;\r\n if (block?.type === \"tool_use\") result.currentTool = String(block.name || \"tool\");\r\n }\r\n if (event.type === \"assistant\" && event.message && typeof event.message === \"object\") {\r\n const content = (event.message as Record<string, unknown>).content;\r\n if (Array.isArray(content)) {\r\n const tool = content.find((item) => item?.type === \"tool_use\") as Record<string, unknown> | undefined;\r\n if (tool) result.currentTool = String(tool.name || result.currentTool);\r\n }\r\n }\r\n if (event.type === \"tool_call\" && event.subtype === \"started\") {\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : undefined;\r\n const name = cursorToolNameFromCall(toolCall);\r\n if (name) result.currentTool = name;\r\n }\r\n const shell = shellPayloadFromCursorEvent(event);\r\n if (shell) {\r\n applyShellOutcome(\r\n result,\r\n classifyShellCommandOutcome({\r\n command: shell.command,\r\n exitCode: shell.exitCode,\r\n stdout: shell.stdout,\r\n stderr: shell.stderr,\r\n interleavedOutput: shell.interleaved,\r\n }),\r\n );\r\n }\r\n if (event.type === \"result\") {\r\n recordStreamResult(result, event);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/** @deprecated Use {@link parseHarnessStream} \u2014 kept for existing imports. */\r\nexport function parseClaudeStream(file: string): ParsedStream {\r\n return parseHarnessStream(file);\r\n}\r\n\r\nexport function summarizeShellToolCallEvent(event: Record<string, unknown>): string | undefined {\r\n const shell = shellPayloadFromCursorEvent(event);\r\n if (!shell) return undefined;\r\n const outcome = classifyShellCommandOutcome({\r\n command: shell.command,\r\n exitCode: shell.exitCode,\r\n stdout: shell.stdout,\r\n stderr: shell.stderr,\r\n interleavedOutput: shell.interleaved,\r\n });\r\n const cmd = oneLine(shell.command).slice(0, 120);\r\n if (outcome.kind === \"audit_findings\") {\r\n return `[audit:findings] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n if (outcome.kind === \"search_no_matches\") {\r\n return `[search:no_matches] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n if (outcome.kind === \"command_failure\") {\r\n return `[command:failed] ${outcome.summary}${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n }\r\n return `[command:ok] exit 0${cmd ? ` \u00B7 ${cmd}` : \"\"}`;\r\n}\r\n\r\nexport function summarizeEvent(event: Record<string, unknown>): string | undefined {\r\n if (event.type === \"system\" && event.subtype) {\r\n return `[system:${event.subtype}] ${String(event.status || event.cwd || \"\")}`.trim();\r\n }\r\n if (event.type === \"stream_event\" && event.event && typeof event.event === \"object\") {\r\n const type = (event.event as Record<string, unknown>).type;\r\n if (type === \"content_block_start\") {\r\n const block = (event.event as Record<string, unknown>).content_block as Record<string, unknown> | undefined;\r\n if (block?.type === \"tool_use\") return `[tool:start] ${block.name}`;\r\n }\r\n if (type === \"content_block_delta\") {\r\n const delta = (event.event as Record<string, unknown>).delta as Record<string, unknown> | undefined;\r\n if (delta?.partial_json) return `[tool:input] ${delta.partial_json}`;\r\n }\r\n if (type === \"message_stop\") return \"[message:stop]\";\r\n return type ? `[stream:${type}]` : undefined;\r\n }\r\n if (event.type === \"assistant\" && event.message && typeof event.message === \"object\") {\r\n const content = (event.message as Record<string, unknown>).content;\r\n if (Array.isArray(content)) {\r\n const text = content.find((item) => item?.type === \"text\") as Record<string, unknown> | undefined;\r\n if (text) return `[assistant] ${oneLine(String(text.text || \"\"))}`;\r\n const tool = content.find((item) => item?.type === \"tool_use\") as Record<string, unknown> | undefined;\r\n if (tool) return `[tool] ${tool.name} ${JSON.stringify(tool.input || {})}`;\r\n }\r\n }\r\n if (event.type === \"user\" && event.tool_use_result) {\r\n const result = event.tool_use_result as Record<string, unknown>;\r\n return `[tool:result] stdout=${JSON.stringify(result.stdout || \"\")} stderr=${JSON.stringify(result.stderr || \"\")}`;\r\n }\r\n if (event.type === \"tool_call\") {\r\n const subtype = String(event.subtype || \"\");\r\n const shellSummary =\r\n subtype === \"completed\" ? summarizeShellToolCallEvent(event) : undefined;\r\n if (shellSummary) return shellSummary;\r\n const toolCall =\r\n event.tool_call && typeof event.tool_call === \"object\" && !Array.isArray(event.tool_call)\r\n ? (event.tool_call as Record<string, unknown>)\r\n : undefined;\r\n const name = cursorToolNameFromCall(toolCall) ?? \"tool\";\r\n return `[tool:${subtype}] ${name}`;\r\n }\r\n if (event.type === \"result\") {\r\n return `[result] ${event.subtype || \"\"} ${oneLine(String(event.result || \"\"))}`.trim();\r\n }\r\n return undefined;\r\n}\r\n", "// Exit normalization for workers that died without a stream-json final result.\r\n//\r\n// When a worker process exits before recording a `result` event, the status path\r\n// used to surface a single generic \"process exited without a final result\"\r\n// needs_attention \u2014 indistinguishable whether the agent crashed mid-task or the\r\n// provider CLI rejected the model/args at startup. That made model/provider\r\n// misconfigurations look like silent stalls the watchdog had to triage by hand.\r\n//\r\n// `classifyExitFailure` inspects the worker's stderr/error tail and, when it\r\n// matches a known startup/config failure (model rejection, missing CLI, auth),\r\n// returns a structured `blocked` classification with a precise reason. The\r\n// status path promotes that to `attention.state = \"blocked\"` \u2014 a real board\r\n// attention state that flows through the harness completion ingest unchanged \u2014\r\n// instead of the catch-all needs_attention.\r\n\r\nexport interface ExitClassification {\r\n /** True when the failure is a structural blocker an operator must fix. */\r\n blocked: boolean;\r\n /** Precise, human-readable reason for the blocker. */\r\n reason: string;\r\n}\r\n\r\ninterface FailurePattern {\r\n test: RegExp;\r\n label: string;\r\n}\r\n\r\n// Ordered most-specific first. Each entry maps a recognizable stderr signature to\r\n// a short blocker label; the matched error tail is appended for context.\r\nconst FAILURE_PATTERNS: FailurePattern[] = [\r\n {\r\n test: /\\b(?:invalid|unknown|unsupported|unrecognized)\\b[^.\\n]*\\bmodel\\b/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /\\bmodel\\b[^.\\n]*\\b(?:not\\s+(?:found|supported|available|recognized|valid)|is\\s+not\\s+valid|does\\s+not\\s+exist)/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /\\b(?:did you mean|available models|choose (?:a|one of)|supported models)\\b/i,\r\n label: \"provider rejected the requested model\",\r\n },\r\n {\r\n test: /model preflight failed/i,\r\n label: \"model/provider preflight failed\",\r\n },\r\n {\r\n test: /\\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\\b/i,\r\n label: \"provider CLI is missing or not on PATH\",\r\n },\r\n {\r\n test: /\\bfailed to spawn\\b/i,\r\n label: \"provider failed to spawn the worker process\",\r\n },\r\n {\r\n test: /\\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\\b/i,\r\n label: \"provider authentication failed\",\r\n },\r\n];\r\n\r\n/** Collapse whitespace and clip a noisy error tail to a single readable line. */\r\nfunction tidy(errorText: string, max = 240): string {\r\n const oneLine = errorText.replace(/\\s+/g, \" \").trim();\r\n return oneLine.length > max ? `${oneLine.slice(0, max - 1)}\u2026` : oneLine;\r\n}\r\n\r\n/**\r\n * Classify a dead worker's error/stderr output. Returns a structured blocker when\r\n * the text matches a known startup/config failure, or null when it does not (the\r\n * caller should fall back to the generic needs_attention path).\r\n */\r\nexport function classifyExitFailure(\r\n errorText: string | null | undefined,\r\n): ExitClassification | null {\r\n const text = (errorText ?? \"\").trim();\r\n if (!text) return null;\r\n for (const pattern of FAILURE_PATTERNS) {\r\n if (pattern.test.test(text)) {\r\n return { blocked: true, reason: `${pattern.label}: ${tidy(text)}` };\r\n }\r\n }\r\n return null;\r\n}\r\n", "// Workers that die without a stream-json `result` event but leave salvageable work\r\n// behind (uncommitted changes and/or commits ahead of the run base). Distinct from\r\n// a generic \"process exited without a final result\" stall \u2014 operators need a\r\n// review-needed signal and a follow-up salvage/landing lane (PR #285 class).\r\n\r\nimport type { GitAncestry } from \"./git.js\";\r\n\r\nexport type ExitedSalvageKind = \"none\" | \"uncommitted\" | \"committed_ahead\" | \"both\";\r\n\r\nexport interface ExitedSalvageAssessment {\r\n kind: ExitedSalvageKind;\r\n /** True when the worktree has reviewable uncommitted and/or committed-ahead work. */\r\n salvageable: boolean;\r\n uncommittedCount: number;\r\n headCommit: string | null;\r\n /** Board / attention reason \u2014 stable prefix for downstream parsers. */\r\n attentionReason: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const trimmed = value.trim();\r\n return trimmed.length ? trimmed : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"boolean\") return value;\r\n if (Array.isArray(value)) return value.length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction committedHeadFromAncestry(ancestry: GitAncestry | null | undefined): string | null {\r\n if (!ancestry?.checked) return null;\r\n if (ancestry.headIsAncestorOfBase !== false) return null;\r\n return trimOrNull(ancestry.head);\r\n}\r\n\r\nfunction buildAttentionReason(\r\n kind: ExitedSalvageKind,\r\n uncommittedCount: number,\r\n headCommit: string | null,\r\n): string {\r\n const parts: string[] = [\"exited_with_changes_salvage\"];\r\n if (kind === \"uncommitted\" || kind === \"both\") {\r\n parts.push(\r\n `${uncommittedCount} uncommitted change${uncommittedCount === 1 ? \"\" : \"s\"} with no final result`,\r\n );\r\n }\r\n if ((kind === \"committed_ahead\" || kind === \"both\") && headCommit) {\r\n const sha = headCommit.length > 12 ? headCommit.slice(0, 12) : headCommit;\r\n parts.push(`commit ${sha} ahead of base with no final result`);\r\n }\r\n parts.push(\"review worktree \u2014 commit, open a PR, or run a salvage worker before discarding\");\r\n return parts.join(\": \");\r\n}\r\n\r\n/**\r\n * Classify a dead worker with no `finalResult`. Returns null when the worker is\r\n * still alive or already recorded a final result.\r\n */\r\nexport function assessExitedWorkerSalvage(input: {\r\n alive: boolean;\r\n finalResult: unknown;\r\n changedFiles?: string[];\r\n gitAncestry?: GitAncestry | null;\r\n headCommit?: string | null;\r\n}): ExitedSalvageAssessment | null {\r\n if (input.alive || hasFinalResult(input.finalResult)) return null;\r\n\r\n const uncommittedCount = (input.changedFiles ?? []).filter((line) => line.trim()).length;\r\n const headCommit = trimOrNull(input.headCommit) ?? committedHeadFromAncestry(input.gitAncestry);\r\n const hasUncommitted = uncommittedCount > 0;\r\n const hasCommittedAhead = Boolean(headCommit);\r\n\r\n if (!hasUncommitted && !hasCommittedAhead) {\r\n return {\r\n kind: \"none\",\r\n salvageable: false,\r\n uncommittedCount: 0,\r\n headCommit: null,\r\n attentionReason: \"process exited without a final result\",\r\n };\r\n }\r\n\r\n const kind: ExitedSalvageKind =\r\n hasUncommitted && hasCommittedAhead ? \"both\" : hasUncommitted ? \"uncommitted\" : \"committed_ahead\";\r\n\r\n return {\r\n kind,\r\n salvageable: true,\r\n uncommittedCount,\r\n headCommit,\r\n attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit),\r\n };\r\n}\r\n", "import type { GitAncestry } from \"./git.js\";\r\n\r\nexport type WorkerLandingBlockReason = \"dirty_worktree_no_pr\";\r\n\r\nexport interface WorkerLandingSnapshot {\r\n finalResult: unknown;\r\n changedFiles: string[];\r\n headCommit?: string | null;\r\n prUrl?: string | null;\r\n artifactBundlePath?: string | null;\r\n patchPath?: string | null;\r\n gitAncestry?: GitAncestry | null;\r\n}\r\n\r\nexport interface WorkerLandingVerdict {\r\n /** When true, do not treat the worker as cleanly landed/done. */\r\n blocked: boolean;\r\n reason?: WorkerLandingBlockReason;\r\n /** Human-readable attention reason for boards and completion payloads. */\r\n detail?: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const trimmed = value.trim();\r\n return trimmed.length ? trimmed : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"boolean\") return value;\r\n if (Array.isArray(value)) return value.length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction hasCommittedLandingRef(snapshot: WorkerLandingSnapshot): boolean {\r\n if (trimOrNull(snapshot.headCommit)) return true;\r\n if (trimOrNull(snapshot.prUrl)) return true;\r\n if (trimOrNull(snapshot.artifactBundlePath)) return true;\r\n if (trimOrNull(snapshot.patchPath)) return true;\r\n const ancestry = snapshot.gitAncestry;\r\n if (ancestry?.checked && ancestry.headIsAncestorOfBase === false && trimOrNull(ancestry.head)) {\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Hard landing gate: a recorded final result is not sufficient when the worker\r\n * left uncommitted code and has no commit/PR/patch/bundle landing path.\r\n */\r\nexport function assessWorkerLanding(snapshot: WorkerLandingSnapshot): WorkerLandingVerdict {\r\n if (!hasFinalResult(snapshot.finalResult)) return { blocked: false };\r\n if (snapshot.changedFiles.length === 0) return { blocked: false };\r\n if (!hasCommittedLandingRef(snapshot)) {\r\n return {\r\n blocked: true,\r\n reason: \"dirty_worktree_no_pr\",\r\n detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s) with no commit or PR; commit, open a PR, or discard before landing`,\r\n };\r\n }\r\n return {\r\n blocked: true,\r\n detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s); commit or discard before landing`,\r\n };\r\n}\r\n\r\nexport function landingAttentionReason(verdict: WorkerLandingVerdict): string | undefined {\r\n if (!verdict.blocked) return undefined;\r\n return verdict.detail ?? verdict.reason ?? \"dirty_worktree_no_pr\";\r\n}\r\n", "// Extract structured harness finalResult JSON embedded in markdown prose.\r\n\r\nfunction tryParseJsonObject(text: string): Record<string, unknown> | null {\r\n const trimmed = text.trim();\r\n if (!trimmed.startsWith(\"{\")) return null;\r\n try {\r\n const parsed: unknown = JSON.parse(trimmed);\r\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction reconciliationEntryCount(record: Record<string, unknown>): number {\r\n const raw =\r\n record.targetPrReconciliation ??\r\n record.target_pr_reconciliation ??\r\n record.targetPrs ??\r\n record.target_prs;\r\n return Array.isArray(raw) ? raw.length : 0;\r\n}\r\n\r\nexport function extractEmbeddedWorkerFinalResultRecord(\r\n value: string,\r\n): Record<string, unknown> | null {\r\n const trimmed = value.trim();\r\n if (!trimmed) return null;\r\n\r\n const direct = tryParseJsonObject(trimmed);\r\n if (direct) return direct;\r\n\r\n const candidates: Record<string, unknown>[] = [];\r\n\r\n const fenceRe = /```(?:json)?\\s*([\\s\\S]*?)```/gi;\r\n let fenceMatch: RegExpExecArray | null;\r\n while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {\r\n const fromFence = tryParseJsonObject(fenceMatch[1] ?? \"\");\r\n if (fromFence) candidates.push(fromFence);\r\n }\r\n\r\n const firstBrace = trimmed.indexOf(\"{\");\r\n const lastBrace = trimmed.lastIndexOf(\"}\");\r\n if (firstBrace >= 0 && lastBrace > firstBrace) {\r\n const slice = tryParseJsonObject(trimmed.slice(firstBrace, lastBrace + 1));\r\n if (slice) candidates.push(slice);\r\n }\r\n\r\n if (candidates.length === 0) return null;\r\n\r\n let best = candidates[candidates.length - 1]!;\r\n let bestScore = reconciliationEntryCount(best);\r\n for (const candidate of candidates) {\r\n const score = reconciliationEntryCount(candidate);\r\n if (score > bestScore) {\r\n best = candidate;\r\n bestScore = score;\r\n }\r\n }\r\n return best;\r\n}\r\n", "// Runtime mirror of server landing-contract gate (Dalton landing-only / target PRs).\r\n\r\nimport { extractEmbeddedWorkerFinalResultRecord } from \"./worker-final-result-embed.js\";\r\nimport type { WorkerLandingSnapshot } from \"./landing-gate.js\";\r\n\r\nexport type TargetPrOutcome = \"merged\" | \"skipped\" | \"blocked\";\r\n\r\nexport interface TargetPrReconciliation {\r\n prUrl: string;\r\n outcome: TargetPrOutcome;\r\n mergeCommit?: string | null;\r\n reason?: string | null;\r\n}\r\n\r\nexport interface WorkerLandingContract {\r\n landingOnly: boolean;\r\n targetPrUrls: string[];\r\n targetPrUrl?: string | null;\r\n repairEnforceOriginalPr?: boolean;\r\n requiresTargetPrReconciliation?: boolean;\r\n}\r\n\r\nexport type WorkerLandingContractBlockReason =\r\n | \"unrelated_implementation_pr\"\r\n | \"missing_target_pr_reconciliation\"\r\n | \"incomplete_target_pr_landing\"\r\n | \"duplicate_repair_pr\"\r\n | \"missing_repair_target_reconciliation\";\r\n\r\nexport interface WorkerLandingContractVerdict {\r\n blocked: boolean;\r\n reason?: WorkerLandingContractBlockReason;\r\n detail?: string;\r\n}\r\n\r\nfunction trimOrNull(value: unknown): string | null {\r\n if (typeof value !== \"string\") return null;\r\n const t = value.trim();\r\n return t.length ? t : null;\r\n}\r\n\r\nfunction hasFinalResult(value: unknown): boolean {\r\n if (value === undefined || value === null) return false;\r\n if (typeof value === \"string\") return value.trim().length > 0;\r\n if (typeof value === \"object\") return Object.keys(value as object).length > 0;\r\n return true;\r\n}\r\n\r\nfunction normalizePrUrl(url: string): string | null {\r\n const m = url\r\n .trim()\r\n .match(/github\\.com\\/([^/]+\\/[^/]+)\\/(?:pull|pulls)\\/(\\d+)/i);\r\n if (!m) return trimOrNull(url);\r\n return `https://github.com/${m[1]}/pull/${m[2]}`;\r\n}\r\n\r\nfunction prUrlSetKey(url: string): string {\r\n const m = url\r\n .trim()\r\n .match(/github\\.com\\/([^/]+\\/[^/]+)\\/(?:pull|pulls)\\/(\\d+)/i);\r\n if (!m) return url.trim().toLowerCase();\r\n return `${m[1].toLowerCase()}/pull/${m[2]}`;\r\n}\r\n\r\nfunction parseReconciliation(finalResult: unknown): TargetPrReconciliation[] {\r\n let record: Record<string, unknown> | null = null;\r\n if (typeof finalResult === \"string\") {\r\n const embedded = extractEmbeddedWorkerFinalResultRecord(finalResult);\r\n if (embedded) record = embedded;\r\n } else if (finalResult && typeof finalResult === \"object\" && !Array.isArray(finalResult)) {\r\n record = finalResult as Record<string, unknown>;\r\n }\r\n if (!record) return [];\r\n const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;\r\n if (!Array.isArray(raw)) return [];\r\n const out: TargetPrReconciliation[] = [];\r\n for (const item of raw) {\r\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\r\n const row = item as Record<string, unknown>;\r\n const prUrl = normalizePrUrl(String(row.prUrl ?? row.pr_url ?? \"\"));\r\n const outcome = trimOrNull(row.outcome);\r\n if (!prUrl || (outcome !== \"merged\" && outcome !== \"skipped\" && outcome !== \"blocked\")) continue;\r\n out.push({\r\n prUrl,\r\n outcome,\r\n mergeCommit: trimOrNull(row.mergeCommit ?? row.merge_commit),\r\n reason: trimOrNull(row.reason),\r\n });\r\n }\r\n return out;\r\n}\r\n\r\n/** Snapshot / structured prUrl only \u2014 not laneExpertise.prUrls citation evidence. */\r\nfunction workerAttachedPrUrls(snapshot: WorkerLandingSnapshot, finalResult: unknown): string[] {\r\n const urls: string[] = [];\r\n const fromSnapshot = normalizePrUrl(trimOrNull(snapshot.prUrl) ?? \"\");\r\n if (fromSnapshot) urls.push(fromSnapshot);\r\n if (finalResult && typeof finalResult === \"object\" && !Array.isArray(finalResult)) {\r\n const record = finalResult as Record<string, unknown>;\r\n const pr = normalizePrUrl(String(record.prUrl ?? record.pr_url ?? \"\"));\r\n if (pr) urls.push(pr);\r\n }\r\n return [...new Set(urls)];\r\n}\r\n\r\nexport function assessWorkerLandingContract(input: {\r\n contract: WorkerLandingContract;\r\n snapshot: WorkerLandingSnapshot;\r\n finalResult?: unknown;\r\n}): WorkerLandingContractVerdict {\r\n const { contract, snapshot } = input;\r\n const finalResult = input.finalResult ?? snapshot.finalResult;\r\n\r\n if (\r\n !contract.landingOnly &&\r\n contract.targetPrUrls.length === 0 &&\r\n !contract.repairEnforceOriginalPr\r\n ) {\r\n return { blocked: false };\r\n }\r\n if (!hasFinalResult(finalResult)) {\r\n const requiresEarly =\r\n contract.requiresTargetPrReconciliation ??\r\n (contract.landingOnly ||\r\n Boolean(contract.repairEnforceOriginalPr) ||\r\n contract.targetPrUrls.length > 0);\r\n if (requiresEarly && contract.targetPrUrls.length > 0) {\r\n return {\r\n blocked: true,\r\n reason: \"missing_target_pr_reconciliation\",\r\n detail: `Final result required to reconcile target PR(s): ${contract.targetPrUrls.join(\", \")}`,\r\n };\r\n }\r\n return { blocked: false };\r\n }\r\n\r\n const requiresTargetPrReconciliation =\r\n contract.requiresTargetPrReconciliation ??\r\n (contract.landingOnly ||\r\n Boolean(contract.repairEnforceOriginalPr) ||\r\n contract.targetPrUrls.length > 0);\r\n\r\n if (!requiresTargetPrReconciliation && !contract.repairEnforceOriginalPr) {\r\n return { blocked: false };\r\n }\r\n\r\n const repairTarget = contract.repairEnforceOriginalPr\r\n ? normalizePrUrl(trimOrNull(contract.targetPrUrl) ?? \"\") ??\r\n (contract.targetPrUrls.length === 1\r\n ? normalizePrUrl(contract.targetPrUrls[0]!)\r\n : null)\r\n : null;\r\n if (repairTarget) {\r\n const workerPrs = workerAttachedPrUrls(snapshot, finalResult);\r\n const supersedes =\r\n finalResult &&\r\n typeof finalResult === \"object\" &&\r\n !Array.isArray(finalResult) &&\r\n (finalResult as Record<string, unknown>).supersedesOriginalTargetPr === true;\r\n if (!supersedes) {\r\n for (const pr of workerPrs) {\r\n if (pr !== repairTarget) {\r\n return {\r\n blocked: true,\r\n reason: \"duplicate_repair_pr\",\r\n detail: `Repair worker opened or attached PR ${pr} instead of canonical target ${repairTarget}`,\r\n };\r\n }\r\n }\r\n }\r\n const reconciliation = parseReconciliation(finalResult);\r\n const entry = reconciliation.find((r) => r.prUrl === repairTarget);\r\n if (\r\n !entry ||\r\n (entry.outcome !== \"merged\" &&\r\n !(entry.reason?.trim() && (entry.outcome === \"skipped\" || entry.outcome === \"blocked\")))\r\n ) {\r\n return {\r\n blocked: true,\r\n reason: \"missing_repair_target_reconciliation\",\r\n detail: `Repair worker must reconcile target PR ${repairTarget}`,\r\n };\r\n }\r\n }\r\n\r\n const reconciliation = parseReconciliation(finalResult);\r\n const byUrl = new Map(\r\n reconciliation.map((r) => [prUrlSetKey(r.prUrl), r] as const),\r\n );\r\n const targetSet = new Set(\r\n contract.targetPrUrls.map((u) => prUrlSetKey(normalizePrUrl(u) ?? u)).filter(Boolean),\r\n );\r\n const attachedPrs = workerAttachedPrUrls(snapshot, finalResult);\r\n\r\n if (contract.landingOnly) {\r\n for (const pr of attachedPrs) {\r\n if (targetSet.size > 0 && !targetSet.has(prUrlSetKey(pr))) {\r\n return {\r\n blocked: true,\r\n reason: \"unrelated_implementation_pr\",\r\n detail: `Landing-only worker attached unrelated PR ${pr}`,\r\n };\r\n }\r\n if (targetSet.size === 0) {\r\n return {\r\n blocked: true,\r\n reason: \"unrelated_implementation_pr\",\r\n detail: \"Landing-only worker must not open new implementation PRs\",\r\n };\r\n }\r\n }\r\n }\r\n\r\n if (contract.targetPrUrls.length === 0) return { blocked: false };\r\n\r\n const missing: string[] = [];\r\n for (const target of contract.targetPrUrls) {\r\n const key = prUrlSetKey(normalizePrUrl(target) ?? target);\r\n const entry = byUrl.get(key);\r\n if (!entry) {\r\n missing.push(key);\r\n continue;\r\n }\r\n if (entry.outcome !== \"merged\" && !entry.reason?.trim()) {\r\n missing.push(key);\r\n }\r\n }\r\n\r\n if (missing.length > 0) {\r\n return {\r\n blocked: true,\r\n reason: missing.every((u) => byUrl.has(u))\r\n ? \"incomplete_target_pr_landing\"\r\n : \"missing_target_pr_reconciliation\",\r\n detail: `Target PR reconciliation incomplete: ${missing.join(\", \")}`,\r\n };\r\n }\r\n\r\n return { blocked: false };\r\n}\r\n\r\nexport function landingContractAttentionReason(\r\n verdict: WorkerLandingContractVerdict,\r\n): string | undefined {\r\n if (!verdict.blocked) return undefined;\r\n return verdict.detail ?? verdict.reason;\r\n}\r\n", "import { parseHeartbeat, terminalFinalResultFromHeartbeat } from \"./heartbeat.js\";\r\nimport { parseHarnessStream } from \"./stream.js\";\r\nimport { classifyExitFailure } from \"./exit-classify.js\";\r\nimport { assessExitedWorkerSalvage } from \"./exited-salvage.js\";\r\nimport { computeGitAncestry, type GitAncestry, gitStatusShort } from \"./git.js\";\r\nimport { assessWorkerLanding, landingAttentionReason } from \"./landing-gate.js\";\r\nimport {\r\n assessWorkerLandingContract,\r\n landingContractAttentionReason,\r\n type WorkerLandingContract,\r\n type TargetPrReconciliation,\r\n} from \"./landing-contract-gate.js\";\r\nimport { extractEmbeddedWorkerFinalResultRecord } from \"./worker-final-result-embed.js\";\r\nimport {\r\n fileMtime,\r\n fileSize,\r\n isPidAlive,\r\n latestIso,\r\n secsAgo,\r\n tailFile,\r\n} from \"./util.js\";\r\n\r\nexport const NO_START_MS = 180_000;\r\nexport const STALE_MS = 600_000;\r\n\r\nexport interface WorkerAttention {\r\n state: \"done\" | \"needs_attention\" | \"blocked\" | \"stale\" | \"ok\";\r\n reason: string;\r\n}\r\n\r\n/** Snapshot of Lane A policy injection at worker spawn (from dispatch-next). */\r\nexport interface InstructionPolicyEvidenceSnapshot {\r\n fingerprint?: string;\r\n ruleSlugs?: string[];\r\n globalRuleCount?: number;\r\n personaRuleCount?: number;\r\n explicitKindCount?: number;\r\n invariantCount?: number;\r\n markdownChars?: number;\r\n injectedAt?: string;\r\n}\r\n\r\n/** Snapshot of task-anchored context envelope injection at worker spawn. */\r\nexport interface ContextEnvelopeEvidenceSnapshot {\r\n anchorTaskId?: string;\r\n envelopeGeneratedAt?: string;\r\n injectedAt?: string;\r\n hasPersonaBlock?: boolean;\r\n personaSlug?: string | null;\r\n operatingRuleCount?: number;\r\n memoryHitCount?: number;\r\n markdownChars?: number;\r\n source?: \"dispatch_injection\" | \"tool_call\";\r\n}\r\n\r\n/** Snapshot of anchored persona context-envelope injection at worker spawn. */\r\nexport interface PersonaContextEvidenceSnapshot {\r\n expectedPersonaSlug?: string;\r\n injectedPersonaSlug?: string;\r\n displayName?: string;\r\n operatingRuleCount?: number;\r\n anchorTaskId?: string;\r\n envelopeGeneratedAt?: string;\r\n injectedAt?: string;\r\n markdownChars?: number;\r\n}\r\n\r\n/** Dispatch-time retrieval probe replayed on harness completion. */\r\nexport interface HarnessMemoryQualityCaptureSnapshot {\r\n memoryQuery: string;\r\n hitCount: number;\r\n miss: boolean;\r\n capturedAt: string;\r\n retrievalEvidence?: Record<string, unknown> | null;\r\n /** P7 privacy-safe prompt block (trace summary + live-verification nudges). */\r\n promptMarkdown?: string | null;\r\n}\r\n\r\nexport interface HarnessWorkerRecord {\r\n name: string;\r\n runId: string;\r\n status: string;\r\n pid?: number;\r\n model?: string;\r\n branch: string;\r\n worktreePath: string;\r\n workerDir: string;\r\n stdoutPath: string;\r\n stderrPath: string;\r\n heartbeatPath: string;\r\n ownedPaths?: string[];\r\n agentOsId?: string;\r\n taskId?: string;\r\n planId?: string;\r\n /** Lane A policy fingerprint when dispatch injected operating rules. */\r\n instructionPolicyFingerprint?: string;\r\n instructionPolicyEvidence?: InstructionPolicyEvidenceSnapshot;\r\n memoryQualityCapture?: HarnessMemoryQualityCaptureSnapshot;\r\n personaSlug?: string;\r\n personaEvidence?: PersonaContextEvidenceSnapshot;\r\n contextEnvelopeEvidence?: ContextEnvelopeEvidenceSnapshot;\r\n leaseOwner?: string;\r\n /** Fencing token from claim \u2014 sent on renew/completion when set. */\r\n leaseToken?: string;\r\n dispatched?: boolean;\r\n startedAt?: string;\r\n /** Routing audit \u2014 which rule selected model/provider (dispatch inference). */\r\n routingRule?: string;\r\n requestedModel?: string;\r\n /** Orchestration provider/model/auth-source/cost audit (no OAuth secrets). */\r\n orchestrationAudit?: import(\"./orchestration-providers/types.js\").OrchestrationRoutingAudit;\r\n /** Board task metadata for landing/PR-handoff gates (set at dispatch). */\r\n executorRef?: string;\r\n parentTaskId?: string;\r\n taskTitle?: string;\r\n taskPrUrl?: string;\r\n /** Canonical target PR for repair workers (must not spawn duplicate PRs). */\r\n repairTargetPrUrl?: string;\r\n repairTargetBranch?: string;\r\n /** Set when stale-reconcile patches a dead/stale worker record. */\r\n reconciledAt?: string;\r\n reconcileReason?: string;\r\n /** Last heartbeat blocker text successfully synced to plan-progress-sync (dedupe). */\r\n lastSyncedHeartbeatBlocker?: string;\r\n /**\r\n * Set when the most recent AgentOS completion replay for this finished worker\r\n * was rejected (e.g. a revoked / expired / cross-workspace runner token) or\r\n * otherwise failed. While set, the worker is NOT treated as cleanly done:\r\n * `finalizeStaleRuns` keeps the run non-terminal and the board surfaces it.\r\n * Cleared once the completion is acknowledged (2xx). Local-only \u2014 never sent\r\n * to the server as part of the worker's intrinsic status.\r\n */\r\n completionBlocker?: string;\r\n /** ISO timestamp when `/harness/completion` returned 2xx for this worker. */\r\n completionReportedAt?: string;\r\n /** Snapshot from the acknowledged completion POST \u2014 local-only. */\r\n completionSnapshot?: { finalResult?: unknown; prUrl?: string | null; summary?: string | null };\r\n /** Audit tag for how `completionReportedAt` was set (`tryCompleteWorker`, `board-task-*`). */\r\n completionAckSource?: string;\r\n /** Local mirror of the last completion POST outcome. */\r\n completionOutcome?: \"acknowledged\" | \"rejected\";\r\n /** Truncated JSON body from the last acknowledged completion response. */\r\n completionResponse?: unknown;\r\n /**\r\n * Direct/local worker with no board linkage \u2014 must not be mistaken for an\r\n * AgentTask-backed harness worker in completion or dispatch paths.\r\n */\r\n localOnly?: boolean;\r\n /** Sidecar PID when detached; used for observability only. */\r\n completionSidecarPid?: number;\r\n completionSidecarSpawnFailedAt?: string;\r\n /** One-off helper paths removed before completion (`kynver worker discard-disposable`). */\r\n disposableArtifactsRemoved?: string[];\r\n /** Physical pool label frozen at spawn for orchestration usage attribution. */\r\n boxKind?: string;\r\n boxId?: string;\r\n /** Runner/daemon identity frozen at spawn (KYNVER_RUNTIME_ID). */\r\n runtimeId?: string;\r\n}\r\n\r\nexport interface RawHarnessWorkerStatus {\r\n runId: string;\r\n worker: string;\r\n pid?: number;\r\n alive: boolean;\r\n status: string;\r\n attention: WorkerAttention;\r\n branch: string;\r\n worktreePath: string;\r\n ownedPaths?: string[];\r\n stdoutBytes: number;\r\n stderrBytes: number;\r\n heartbeatBytes: number;\r\n firstEventAt: string | null;\r\n lastEventAt: string | null;\r\n lastActivityAt: string | null;\r\n currentTool: string | null;\r\n heartbeatCount: number;\r\n lastHeartbeatAt: string | null;\r\n lastHeartbeatPhase: string | null;\r\n lastHeartbeatSummary: string | null;\r\n heartbeatBlocker: string | null;\r\n /** Parser-detected timestamp anomalies (e.g., future heartbeat ts). */\r\n timestampAnomalies?: Array<{\r\n kind: \"future_heartbeat_timestamp\";\r\n observedAt: string;\r\n clampedTo: string;\r\n }>;\r\n finalResult: unknown;\r\n error?: string;\r\n changedFiles: string[];\r\n gitAncestry: GitAncestry;\r\n /** Set by PR-ready handoff before completion is posted. */\r\n prUrl?: string;\r\n headCommit?: string;\r\n /** Paths removed via `kynver worker discard-disposable` before completion POST. */\r\n disposableArtifactsRemoved?: string[];\r\n /** Fencing token from claim \u2014 echoed on completion when set. */\r\n leaseToken?: string;\r\n /** Lane A policy fields echoed on completion status for mirror recovery. */\r\n instructionPolicyFingerprint?: string | null;\r\n instructionPolicyEvidence?: InstructionPolicyEvidenceSnapshot | null;\r\n /** Model the worker was launched with \u2014 echoed from worker.json for usage tracking. */\r\n model?: string | null;\r\n /** Orchestration provider key (codex | cursor | claude) \u2014 echoed from worker.json. */\r\n provider?: string | null;\r\n /** Physical pool label \u2014 ghost | forge (runtime \u2265 0.1.115). */\r\n boxKind?: string | null;\r\n boxId?: string | null;\r\n /** Runner/daemon identity echoed from worker.json. */\r\n runtimeId?: string | null;\r\n personaSlug?: string | null;\r\n /** True when dispatch-next spawned the worker on a daemon tick. */\r\n dispatched?: boolean | null;\r\n localOnly?: boolean | null;\r\n}\r\n\r\nexport interface WorkerStatusOptions {\r\n /** Branch ref for ancestry when baseCommit is not set. */\r\n base?: string;\r\n /** Pinned SHA from run creation \u2014 preferred for ancestry vs a moving branch tip. */\r\n baseCommit?: string;\r\n}\r\n\r\nexport function computeAttention(input: {\r\n alive: boolean;\r\n finalResult: unknown;\r\n firstEventAt: string | null;\r\n stdoutBytes: number;\r\n stderrBytes?: number;\r\n heartbeatBytes: number;\r\n lastActivityAt: string | null;\r\n heartbeatBlocker: string | null;\r\n startedAt?: string;\r\n /** stderr tail / parsed error for a worker that died without a final result. */\r\n error?: string | null;\r\n changedFiles?: string[];\r\n gitAncestry?: GitAncestry | null;\r\n completionBlocker?: string | null;\r\n landingContract?: WorkerLandingContract | null;\r\n prUrl?: string | null;\r\n localOnly?: boolean;\r\n taskId?: string | null;\r\n agentOsId?: string | null;\r\n reconcileReason?: string | null;\r\n}): WorkerAttention {\r\n const now = Date.now();\r\n if (input.completionBlocker && !isSkippedTerminalCompletionBlocker(input.completionBlocker)) {\r\n return { state: \"blocked\", reason: input.completionBlocker };\r\n }\r\n if (input.finalResult) {\r\n if (input.localOnly && hasMergedTargetPrReconciliation(input.finalResult)) {\r\n return { state: \"done\", reason: \"local-only worker superseded by merged PR\" };\r\n }\r\n const landingSnapshot = {\r\n finalResult: input.finalResult,\r\n changedFiles: input.changedFiles ?? [],\r\n gitAncestry: input.gitAncestry ?? null,\r\n prUrl: input.prUrl ?? null,\r\n };\r\n const landing = assessWorkerLanding(landingSnapshot);\r\n if (landing.blocked) {\r\n const detail = landingAttentionReason(landing);\r\n return {\r\n state: \"needs_attention\",\r\n reason: landing.reason\r\n ? `landing blocked (${landing.reason}): ${detail}`\r\n : `landing blocked: ${detail}`,\r\n };\r\n }\r\n if (input.landingContract) {\r\n const contractVerdict = assessWorkerLandingContract({\r\n contract: input.landingContract,\r\n snapshot: landingSnapshot,\r\n finalResult: input.finalResult,\r\n });\r\n const contractDetail = landingContractAttentionReason(contractVerdict);\r\n if (contractDetail) {\r\n return {\r\n state: \"needs_attention\",\r\n reason: contractVerdict.reason\r\n ? `landing contract (${contractVerdict.reason}): ${contractDetail}`\r\n : `landing contract: ${contractDetail}`,\r\n };\r\n }\r\n }\r\n return { state: \"done\", reason: \"final result recorded\" };\r\n }\r\n if (!input.alive) {\r\n if (isAbandonedEmptyWorker(input)) {\r\n return { state: \"done\", reason: \"empty abandoned worker record\" };\r\n }\r\n // A worker that exited without a final result is not always a silent stall:\r\n // a recognizable startup/config failure (model/provider rejection, missing\r\n // CLI, auth) is a structural blocker, not a generic needs_attention.\r\n const classified = classifyExitFailure(input.error);\r\n if (classified) return { state: \"blocked\", reason: classified.reason };\r\n const salvage = assessExitedWorkerSalvage({\r\n alive: false,\r\n finalResult: null,\r\n changedFiles: input.changedFiles,\r\n gitAncestry: input.gitAncestry,\r\n });\r\n if (salvage?.salvageable) {\r\n const tail = input.error?.trim();\r\n return {\r\n state: \"needs_attention\",\r\n reason: tail ? `${salvage.attentionReason} (${tail})` : salvage.attentionReason,\r\n };\r\n }\r\n const tail = input.error?.trim();\r\n return {\r\n state: \"needs_attention\",\r\n reason: tail\r\n ? `process exited without a final result: ${tail}`\r\n : salvage?.attentionReason ?? \"process exited without a final result\",\r\n };\r\n }\r\n if (input.heartbeatBlocker) {\r\n return { state: \"blocked\", reason: `worker heartbeat reported blocker: ${input.heartbeatBlocker}` };\r\n }\r\n const startMs = input.startedAt ? Date.parse(input.startedAt) : NaN;\r\n if (\r\n !input.firstEventAt &&\r\n input.stdoutBytes === 0 &&\r\n input.heartbeatBytes === 0 &&\r\n Number.isFinite(startMs) &&\r\n now - startMs > NO_START_MS\r\n ) {\r\n return { state: \"needs_attention\", reason: `no first stream event ${secsAgo(startMs)}s after start` };\r\n }\r\n const actMs = input.lastActivityAt ? Date.parse(input.lastActivityAt) : NaN;\r\n if (Number.isFinite(actMs) && now - actMs > STALE_MS) {\r\n return { state: \"stale\", reason: `no log/event/heartbeat activity for ${secsAgo(actMs)}s` };\r\n }\r\n return { state: \"ok\", reason: \"recent activity\" };\r\n}\r\n\r\nfunction isSkippedTerminalCompletionBlocker(reason: string | null | undefined): boolean {\r\n const text = reason?.trim();\r\n if (!text) return false;\r\n return /completion acknowledged but board not advanced/i.test(text) && /task already terminal/i.test(text);\r\n}\r\n\r\nfunction isAbandonedEmptyWorker(input: {\r\n finalResult: unknown;\r\n stdoutBytes: number;\r\n stderrBytes?: number;\r\n heartbeatBytes: number;\r\n changedFiles?: string[];\r\n error?: string | null;\r\n taskId?: string | null;\r\n agentOsId?: string | null;\r\n reconcileReason?: string | null;\r\n}): boolean {\r\n if (input.finalResult) return false;\r\n if (input.taskId || input.agentOsId) return false;\r\n if (input.stdoutBytes > 0 || (input.stderrBytes ?? 0) > 0 || input.heartbeatBytes > 0) return false;\r\n if (input.error?.trim()) return false;\r\n if ((input.changedFiles ?? []).some((line) => line.trim())) return false;\r\n return /empty worker dir|marked abandoned/i.test(input.reconcileReason ?? \"\");\r\n}\r\n\r\nfunction hasMergedTargetPrReconciliation(value: unknown): boolean {\r\n let record: Record<string, unknown> | null = null;\r\n if (typeof value === \"string\") record = extractEmbeddedWorkerFinalResultRecord(value);\r\n else if (value && typeof value === \"object\" && !Array.isArray(value)) record = value as Record<string, unknown>;\r\n if (!record) return false;\r\n const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;\r\n if (!Array.isArray(raw)) return false;\r\n return raw.some((item): item is TargetPrReconciliation => {\r\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return false;\r\n return String((item as Record<string, unknown>).outcome ?? \"\").trim() === \"merged\";\r\n });\r\n}\r\n\r\nfunction resolveFinalResult(\r\n worker: HarnessWorkerRecord,\r\n parsedFinalResult: unknown,\r\n heartbeat: ReturnType<typeof parseHeartbeat>,\r\n): unknown {\r\n const ackSnapshot = worker.completionSnapshot?.finalResult;\r\n if (worker.completionAckSource === \"local-pr-merged-reconcile\" && ackSnapshot !== undefined && ackSnapshot !== null) {\r\n return ackSnapshot;\r\n }\r\n if (parsedFinalResult) return parsedFinalResult;\r\n if (ackSnapshot !== undefined && ackSnapshot !== null) return ackSnapshot;\r\n return terminalFinalResultFromHeartbeat(heartbeat);\r\n}\r\n\r\nexport function computeWorkerStatus(worker: HarnessWorkerRecord, options: WorkerStatusOptions = {}): RawHarnessWorkerStatus {\r\n const parsed = parseHarnessStream(worker.stdoutPath);\r\n const heartbeat = parseHeartbeat(worker.heartbeatPath);\r\n const completionAcknowledged =\r\n typeof worker.completionReportedAt === \"string\" && worker.completionReportedAt.trim().length > 0;\r\n const finalResult = resolveFinalResult(worker, parsed.finalResult, heartbeat);\r\n const alive = completionAcknowledged ? false : isPidAlive(worker.pid);\r\n const stdoutBytes = fileSize(worker.stdoutPath);\r\n const stderrBytes = fileSize(worker.stderrPath);\r\n const heartbeatBytes = fileSize(worker.heartbeatPath);\r\n const changedFiles = gitStatusShort(worker.worktreePath);\r\n const gitAncestry = computeGitAncestry(worker.worktreePath, {\r\n base: options.base,\r\n baseCommit: options.baseCommit,\r\n });\r\n const lastActivityAt = latestIso([\r\n parsed.lastEventAt,\r\n heartbeat.lastHeartbeatAt,\r\n fileMtime(worker.stdoutPath),\r\n fileMtime(worker.stderrPath),\r\n fileMtime(worker.heartbeatPath),\r\n ]);\r\n // The error surfaced when a worker died without a final result: the parsed\r\n // stream error, else the stderr tail. Computed before attention so a startup/\r\n // config failure can be classified as a structured blocker.\r\n const error =\r\n parsed.error ||\r\n (!alive && !finalResult ? tailFile(worker.stderrPath, 10).trim() || undefined : undefined);\r\n const completionBlocker =\r\n typeof worker.completionBlocker === \"string\" && worker.completionBlocker.trim()\r\n ? worker.completionBlocker.trim()\r\n : null;\r\n const effectiveCompletionBlocker = isSkippedTerminalCompletionBlocker(completionBlocker)\r\n ? null\r\n : completionBlocker;\r\n const landingContract: WorkerLandingContract | null = worker.repairTargetPrUrl\r\n ? {\r\n landingOnly: false,\r\n targetPrUrls: [worker.repairTargetPrUrl],\r\n targetPrUrl: worker.repairTargetPrUrl,\r\n repairEnforceOriginalPr: true,\r\n }\r\n : null;\r\n\r\n const attention = computeAttention({\r\n alive,\r\n finalResult,\r\n firstEventAt: parsed.firstEventAt,\r\n stdoutBytes,\r\n stderrBytes,\r\n heartbeatBytes,\r\n lastActivityAt,\r\n heartbeatBlocker: heartbeat.heartbeatBlocker,\r\n startedAt: worker.startedAt,\r\n error,\r\n changedFiles,\r\n gitAncestry,\r\n completionBlocker: effectiveCompletionBlocker,\r\n landingContract,\r\n prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? null,\r\n localOnly: worker.localOnly === true,\r\n taskId: worker.taskId ?? null,\r\n agentOsId: worker.agentOsId ?? null,\r\n reconcileReason: worker.reconcileReason ?? null,\r\n });\r\n const workerStatusLabel =\r\n effectiveCompletionBlocker || attention.state === \"blocked\"\r\n ? \"blocked\"\r\n : completionAcknowledged || attention.state === \"done\"\r\n ? \"done\"\r\n : finalResult\r\n ? \"exited\"\r\n : alive\r\n ? \"running\"\r\n : \"exited\";\r\n return {\r\n runId: worker.runId,\r\n worker: worker.name,\r\n pid: worker.pid,\r\n alive,\r\n status: workerStatusLabel,\r\n attention,\r\n branch: worker.branch,\r\n worktreePath: worker.worktreePath,\r\n ownedPaths: worker.ownedPaths,\r\n stdoutBytes,\r\n stderrBytes,\r\n heartbeatBytes,\r\n firstEventAt: parsed.firstEventAt,\r\n lastEventAt: parsed.lastEventAt,\r\n lastActivityAt,\r\n currentTool: completionAcknowledged ? null : parsed.currentTool,\r\n heartbeatCount: heartbeat.heartbeatCount,\r\n lastHeartbeatAt: heartbeat.lastHeartbeatAt,\r\n lastHeartbeatPhase: heartbeat.lastHeartbeatPhase,\r\n lastHeartbeatSummary: heartbeat.lastHeartbeatSummary,\r\n heartbeatBlocker: heartbeat.heartbeatBlocker,\r\n timestampAnomalies: heartbeat.timestampAnomalies,\r\n finalResult,\r\n error,\r\n changedFiles,\r\n gitAncestry,\r\n instructionPolicyFingerprint: worker.instructionPolicyFingerprint ?? null,\r\n instructionPolicyEvidence: worker.instructionPolicyEvidence ?? null,\r\n model: worker.model ?? worker.orchestrationAudit?.model ?? null,\r\n provider: worker.orchestrationAudit?.provider ?? null,\r\n boxKind: worker.boxKind ?? null,\r\n boxId: worker.boxId ?? null,\r\n runtimeId: worker.runtimeId ?? null,\r\n personaSlug: worker.personaSlug ?? null,\r\n dispatched: worker.dispatched ?? null,\r\n localOnly: worker.localOnly ?? null,\r\n };\r\n}\r\n\r\nexport function isFinishedWorkerStatus(status: RawHarnessWorkerStatus): boolean {\r\n if (status.finalResult) return true;\r\n if (status.alive === false) return true;\r\n if (status.status === \"exited\" || status.status === \"done\") return true;\r\n return false;\r\n}\r\n\r\n/** True when a worker recorded a final result but failed the landing gate. */\r\nexport function isLandingBlockedWorkerStatus(status: RawHarnessWorkerStatus): boolean {\r\n if (!status.finalResult) return false;\r\n return status.attention.state === \"needs_attention\" || status.attention.state === \"blocked\";\r\n}\r\n\r\nexport function deriveRunStatus(fallback: string, workers: Array<{ attention?: string; status?: string }>): string {\r\n if (workers.length === 0) return fallback;\r\n if (workers.some((w) => w.attention === \"needs_attention\" || w.attention === \"stale\" || w.attention === \"blocked\")) {\r\n return \"needs_attention\";\r\n }\r\n if (workers.every((w) => w.status === \"done\")) return \"done\";\r\n if (workers.some((w) => w.status === \"running\")) return \"running\";\r\n return fallback;\r\n}\r\n", "import { readFileSync } from \"node:fs\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\nimport { computeWorkerStatus } from \"./status.js\";\r\n\r\nfunction pidCommandLine(pid: number | undefined): string | null {\r\n if (!pid || process.platform !== \"linux\") return null;\r\n try {\r\n return readFileSync(`/proc/${pid}/cmdline`, \"utf8\").replace(/\\0/g, \" \");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * PID existence is not enough on long-running hosts: Linux can reuse an old\r\n * worker PID for an unrelated process, which makes stale worker.json records\r\n * look alive and can falsely saturate the global worker gate.\r\n */\r\nexport function workerProcessMatchesRecord(worker: HarnessWorkerRecord): boolean {\r\n if (!worker.pid || process.platform !== \"linux\") return true;\r\n const cmdline = pidCommandLine(worker.pid);\r\n if (!cmdline) return false;\r\n const probes = [worker.worktreePath, worker.workerDir, worker.heartbeatPath].filter(\r\n (value): value is string => typeof value === \"string\" && value.trim().length > 0,\r\n );\r\n return probes.some((probe) => cmdline.includes(probe));\r\n}\r\n\r\n/**\r\n * Whether a worker still occupies a machine-wide harness capacity slot.\r\n * Ignores completion-acknowledged workers even when the recorded PID was reused.\r\n */\r\nexport function isActiveHarnessWorker(worker: HarnessWorkerRecord): boolean {\r\n if (typeof worker.completionBlocker === \"string\" && worker.completionBlocker.trim()) {\r\n return false;\r\n }\r\n const status = computeWorkerStatus(worker);\r\n if (status.alive && !workerProcessMatchesRecord(worker)) return false;\r\n return status.alive && !status.finalResult && status.attention.state !== \"done\";\r\n}\r\n", "import os from \"node:os\";\r\nimport { readMemAvailableBytes } from \"./bounded-build/meminfo.js\";\r\nimport path from \"node:path\";\r\nimport { loadUserConfig, type KynverUserConfig } from \"./config.js\";\r\nimport { resolveBoxKindFromConfig } from \"./box-identity.js\";\r\nimport type { WorkerCapSource } from \"./worker-cap-source.js\";\r\nimport { resolveWorkerCap } from \"./worker-cap-source.js\";\r\nimport type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport { observeRunnerDiskGate } from \"./disk-gate.js\";\r\nimport { listRunRecords, loadRun, runDirectory, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { listRunWorkerNames } from \"./run-worker-index.js\";\r\nimport { isActiveHarnessWorker, workerProcessMatchesRecord } from \"./harness-worker-active.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport { workerProcessMatchesRecord };\r\n\r\n/** Default RAM budget per worker (~500 MiB, dogfood measured). Internal \u2014 not a setup knob. */\r\nexport const DEFAULT_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;\r\n\r\n/** Keep headroom for OS / IDE. Internal \u2014 not a setup knob. */\r\nexport const DEFAULT_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;\r\n\r\n/** Fraction of total RAM used when auto-sizing worker cap. Internal. */\r\nexport const DEFAULT_MEM_UTILIZATION = 0.85;\r\n\r\n/** Auto cap when the user has not set maxConcurrentWorkers (safety on huge hosts). */\r\nexport const AUTO_MAX_WORKERS_CEILING = 64;\r\n\r\nexport interface RunnerResourceGateShape {\r\n ok: boolean;\r\n totalMemBytes: number;\r\n freeMemBytes: number;\r\n memReserveBytes: number;\r\n perWorkerMemBytes: number;\r\n configuredMaxWorkers: number | null;\r\n /** Where the effective worker cap was resolved (workspace override, env, config, or auto). */\r\n workerCapSource: WorkerCapSource;\r\n /** Physical pool for this host (`forge` | `ghost`). */\r\n boxKind: string;\r\n autoCap: number;\r\n capacityWorkers: number;\r\n maxConcurrentWorkers: number;\r\n activeWorkers: number;\r\n slotsAvailable: number;\r\n reason: string | null;\r\n /** Present unless `KYNVER_RESOURCE_GATE_SKIP_DISK=1`. */\r\n diskGate?: DispatchNextDiskGateShape;\r\n}\r\n\r\nexport interface ObserveResourceGateInput {\r\n runId: string;\r\n config?: KynverUserConfig;\r\n /** Command Center / workspace override \u2014 wins over local config when set. */\r\n configuredMaxWorkersOverride?: number | null;\r\n /** Override active worker count (tests). */\r\n activeWorkers?: number;\r\n totalMemBytes?: number;\r\n freeMemBytes?: number;\r\n diskPath?: string;\r\n skipDiskGate?: boolean;\r\n}\r\n\r\nfunction positiveInt(value: unknown, fallback: number): number {\r\n const n = Number(value);\r\n if (!Number.isFinite(n) || n <= 0) return fallback;\r\n return Math.floor(n);\r\n}\r\n\r\nfunction resolveResourceConfig(\r\n config: KynverUserConfig = loadUserConfig(),\r\n configuredMaxWorkersOverride?: number | null,\r\n totalMemBytes?: number,\r\n) {\r\n const perWorkerMemBytes = positiveInt(config.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES);\r\n const memReserveBytes = positiveInt(config.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES);\r\n const memUtilization = Math.min(\r\n 1,\r\n Math.max(0.1, Number(config.memUtilization) > 0 ? Number(config.memUtilization) : DEFAULT_MEM_UTILIZATION),\r\n );\r\n const cap = resolveWorkerCap({\r\n config,\r\n configuredMaxWorkersOverride,\r\n totalMemBytes: totalMemBytes ?? os.totalmem(),\r\n });\r\n return {\r\n perWorkerMemBytes,\r\n memReserveBytes,\r\n memUtilization,\r\n configuredMaxWorkers: cap.configuredMaxWorkers,\r\n autoCap: cap.autoCap,\r\n workerCapSource: cap.workerCapSource,\r\n };\r\n}\r\n\r\n/** How many workers this host could run from RAM alone (before a user cap). */\r\nexport function computeAutoMaxWorkers(\r\n totalMemBytes: number,\r\n opts: { perWorkerMemBytes?: number; memReserveBytes?: number; memUtilization?: number } = {},\r\n): number {\r\n const perWorkerMemBytes = opts.perWorkerMemBytes ?? DEFAULT_PER_WORKER_MEM_BYTES;\r\n const memReserveBytes = opts.memReserveBytes ?? DEFAULT_MEM_RESERVE_BYTES;\r\n const memUtilization = opts.memUtilization ?? DEFAULT_MEM_UTILIZATION;\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);\r\n const raw = Math.max(1, Math.floor(budgetBytes / perWorkerMemBytes));\r\n return Math.min(raw, AUTO_MAX_WORKERS_CEILING);\r\n}\r\n\r\nfunction readAvailableMemBytes(): number {\r\n return readMemAvailableBytes();\r\n}\r\n\r\n/** Count alive, still-executing workers in a single run record. */\r\nfunction countActiveWorkersForRun(run: HarnessRunRecord): number {\r\n let active = 0;\r\n for (const name of listRunWorkerNames(run)) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectory(run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker || !isActiveHarnessWorker(worker)) continue;\r\n active++;\r\n }\r\n return active;\r\n}\r\n\r\n/** Count active workers in ONE run (kept for callers/tests scoped to a run). */\r\nexport function countActiveWorkers(runId: string): number {\r\n return countActiveWorkersForRun(loadRun(runId));\r\n}\r\n\r\n/**\r\n * Count active workers across EVERY run on disk. The harness creates a new run\r\n * per task, so a per-run count let concurrent runs each believe the machine was\r\n * idle \u2014 the configured cap was never a real global ceiling (the \"spawns 4 or\r\n * infinity, never N\" bug). This machine-wide count is what the gate must use.\r\n */\r\nexport function countActiveWorkersGlobal(): number {\r\n let active = 0;\r\n for (const run of listRunRecords()) active += countActiveWorkersForRun(run);\r\n return active;\r\n}\r\n\r\n/**\r\n * Compute how many workers this host can run and how many dispatch slots remain.\r\n * Uses total RAM for steady-state capacity and free RAM as a hard safety gate.\r\n */\r\nexport function observeRunnerResourceGate(input: ObserveResourceGateInput): RunnerResourceGateShape {\r\n const config = input.config ?? loadUserConfig();\r\n const totalMemBytes = input.totalMemBytes ?? os.totalmem();\r\n const { perWorkerMemBytes, memReserveBytes, memUtilization, configuredMaxWorkers, autoCap: resolvedAutoCap, workerCapSource } =\r\n resolveResourceConfig(config, input.configuredMaxWorkersOverride, totalMemBytes);\r\n const boxKind = resolveBoxKindFromConfig(config);\r\n const freeMemBytes = input.freeMemBytes ?? readAvailableMemBytes();\r\n // Active count is GLOBAL across all runs (see countActiveWorkersGlobal), so the\r\n // cap is a true machine-wide ceiling rather than per-run.\r\n const activeWorkers = input.activeWorkers ?? countActiveWorkersGlobal();\r\n\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);\r\n const capacityFromTotal = Math.max(0, Math.floor(budgetBytes / perWorkerMemBytes));\r\n const capacityFromFree = Math.max(0, Math.floor(Math.max(0, freeMemBytes - memReserveBytes) / perWorkerMemBytes));\r\n\r\n const autoCap = resolvedAutoCap;\r\n const targetCap = configuredMaxWorkers ?? autoCap;\r\n const maxConcurrentWorkers = Math.max(0, Math.min(targetCap, capacityFromTotal));\r\n const slotsByCapacity = Math.max(0, maxConcurrentWorkers - activeWorkers);\r\n // capacityFromFree is ADDITIONAL headroom: free/available RAM already excludes\r\n // memory held by running workers, so we must NOT subtract activeWorkers again.\r\n // Doing so (the old `capacityFromFree - activeWorkers`) double-counted active\r\n // workers and collapsed dispatch to a handful of slots under load.\r\n const slotsByFreeMem = capacityFromFree;\r\n let slotsAvailable = Math.min(slotsByCapacity, slotsByFreeMem);\r\n\r\n const skipDisk = input.skipDiskGate || process.env.KYNVER_RESOURCE_GATE_SKIP_DISK === \"1\";\r\n const diskGate = skipDisk\r\n ? undefined\r\n : observeRunnerDiskGate({\r\n diskPath:\r\n input.diskPath?.trim() ||\r\n process.env.KYNVER_DISK_GUARD_PATH?.trim() ||\r\n \"/\",\r\n });\r\n if (diskGate && !diskGate.ok) slotsAvailable = 0;\r\n\r\n let reason: string | null = null;\r\n if (slotsAvailable <= 0) {\r\n if (diskGate && !diskGate.ok) {\r\n reason = diskGate.reason ?? \"disk gate blocked worker admission\";\r\n } else if (activeWorkers >= maxConcurrentWorkers) {\r\n reason = `at worker limit (${activeWorkers}/${maxConcurrentWorkers} running)`;\r\n } else if (capacityFromFree <= 0) {\r\n reason = \"insufficient free memory \u2014 waiting for workers to finish\";\r\n } else {\r\n reason = \"no worker slots available\";\r\n }\r\n }\r\n\r\n return {\r\n ok: slotsAvailable > 0,\r\n totalMemBytes,\r\n freeMemBytes,\r\n memReserveBytes,\r\n perWorkerMemBytes,\r\n configuredMaxWorkers,\r\n workerCapSource,\r\n boxKind,\r\n autoCap,\r\n capacityWorkers: capacityFromTotal,\r\n maxConcurrentWorkers,\r\n activeWorkers,\r\n slotsAvailable,\r\n reason,\r\n ...(diskGate ? { diskGate } : {}),\r\n };\r\n}\r\n", "import type { KynverUserConfig } from \"./config.js\";\r\nimport {\r\n AUTO_MAX_WORKERS_CEILING,\r\n computeAutoMaxWorkers,\r\n DEFAULT_MEM_RESERVE_BYTES,\r\n DEFAULT_MEM_UTILIZATION,\r\n DEFAULT_PER_WORKER_MEM_BYTES,\r\n} from \"./resource-gate.js\";\r\n\r\nexport type WorkerCapSource = \"workspace_override\" | \"env\" | \"config\" | \"auto\";\r\n\r\nexport interface ResolvedWorkerCap {\r\n configuredMaxWorkers: number | null;\r\n autoCap: number;\r\n workerCapSource: WorkerCapSource;\r\n}\r\n\r\nfunction positiveInt(value: unknown, fallback: number): number {\r\n const n = Number(value);\r\n if (!Number.isFinite(n) || n <= 0) return fallback;\r\n return Math.floor(n);\r\n}\r\n\r\nexport function resolveWorkerCap(\r\n input: {\r\n config?: KynverUserConfig;\r\n configuredMaxWorkersOverride?: number | null;\r\n totalMemBytes: number;\r\n env?: NodeJS.ProcessEnv;\r\n },\r\n): ResolvedWorkerCap {\r\n const config = input.config ?? {};\r\n const env = input.env ?? process.env;\r\n const perWorkerMemBytes = positiveInt(config.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES);\r\n const memReserveBytes = positiveInt(config.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES);\r\n const memUtilization = Math.min(\r\n 1,\r\n Math.max(0.1, Number(config.memUtilization) > 0 ? Number(config.memUtilization) : DEFAULT_MEM_UTILIZATION),\r\n );\r\n const autoCap = computeAutoMaxWorkers(input.totalMemBytes, {\r\n perWorkerMemBytes,\r\n memReserveBytes,\r\n memUtilization,\r\n });\r\n\r\n if (input.configuredMaxWorkersOverride !== undefined && input.configuredMaxWorkersOverride !== null) {\r\n return {\r\n configuredMaxWorkers: positiveInt(input.configuredMaxWorkersOverride, autoCap),\r\n autoCap,\r\n workerCapSource: \"workspace_override\",\r\n };\r\n }\r\n\r\n if (config.maxConcurrentWorkers !== undefined && config.maxConcurrentWorkers !== null) {\r\n const configured = positiveInt(config.maxConcurrentWorkers, 0) || null;\r\n if (configured) {\r\n return {\r\n configuredMaxWorkers: Math.min(configured, AUTO_MAX_WORKERS_CEILING),\r\n autoCap,\r\n workerCapSource: \"config\",\r\n };\r\n }\r\n }\r\n\r\n const envIntentional =\r\n env.KYNVER_MAX_WORKERS_INTENTIONAL === \"1\" || env.KYNVER_MAX_WORKERS_INTENTIONAL === \"true\";\r\n const envCap = envIntentional && env.KYNVER_MAX_WORKERS ? positiveInt(env.KYNVER_MAX_WORKERS, 0) || null : null;\r\n if (envCap) {\r\n return {\r\n configuredMaxWorkers: Math.min(envCap, AUTO_MAX_WORKERS_CEILING),\r\n autoCap,\r\n workerCapSource: \"env\",\r\n };\r\n }\r\n\r\n return {\r\n configuredMaxWorkers: null,\r\n autoCap,\r\n workerCapSource: \"auto\",\r\n };\r\n}\r\n\r\nexport interface SetupWorkerCapRecommendation {\r\n totalMemBytes: number;\r\n autoCap: number;\r\n recommendedMaxWorkers: number;\r\n diskPath: string;\r\n diskGateOk: boolean;\r\n diskFreeBytes: number | null;\r\n}\r\n\r\n/** RAM/disk-aware default for `kynver setup` when the operator omits --max-workers. */\r\nexport function recommendSetupWorkerCap(\r\n input: {\r\n totalMemBytes?: number;\r\n diskPath?: string;\r\n diskGateOk?: boolean;\r\n diskFreeBytes?: number | null;\r\n config?: KynverUserConfig;\r\n } = {},\r\n): SetupWorkerCapRecommendation {\r\n const totalMemBytes = input.totalMemBytes ?? 0;\r\n const autoCap = computeAutoMaxWorkers(totalMemBytes, {\r\n perWorkerMemBytes: positiveInt(input.config?.perWorkerMemBytes, DEFAULT_PER_WORKER_MEM_BYTES),\r\n memReserveBytes: positiveInt(input.config?.memReserveBytes, DEFAULT_MEM_RESERVE_BYTES),\r\n memUtilization:\r\n input.config?.memUtilization && Number(input.config.memUtilization) > 0\r\n ? Number(input.config.memUtilization)\r\n : DEFAULT_MEM_UTILIZATION,\r\n });\r\n const diskGateOk = input.diskGateOk ?? true;\r\n const recommendedMaxWorkers = diskGateOk ? autoCap : Math.max(1, Math.min(autoCap, 4));\r\n return {\r\n totalMemBytes,\r\n autoCap,\r\n recommendedMaxWorkers,\r\n diskPath: input.diskPath ?? \"/\",\r\n diskGateOk,\r\n diskFreeBytes: input.diskFreeBytes ?? null,\r\n };\r\n}\r\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\r\nimport { homedir, totalmem } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { discoverDefaultRepo } from \"./default-repo-discovery.js\";\r\nimport { displayUserPath, redactHomePath } from \"./path-values.js\";\r\nimport { trimTrailingSlash } from \"./util.js\";\r\nimport { normalizeWorkerPoolBoxKind, resolveBoxIdentity } from \"./box-identity.js\";\r\nimport { recommendSetupWorkerCap } from \"./worker-cap-source.js\";\r\nimport { observeRunnerDiskGate } from \"./disk-gate.js\";\r\nimport os from \"node:os\";\r\n\r\nexport interface KynverUserConfig {\r\n apiBaseUrl?: string;\r\n agentOsSlug?: string;\r\n agentOsId?: string;\r\n defaultRepo?: string;\r\n workerProvider?: string;\r\n /** Default Claude model when dispatch does not infer or pass `--model`. */\r\n defaultModel?: string;\r\n harnessRoot?: string;\r\n /**\r\n * Operator attestation that the hosted Kynver deployment uses this scheduler provider\r\n * (set on user runners after Vercel env cutover \u2014 scheduling is deployment-owned).\r\n */\r\n deploymentSchedulerProvider?: \"qstash\" | \"kynver-cron\" | \"openclaw-cron\";\r\n /** Default harness run for `kynver daemon` / systemd user unit (set by `kynver cron install`). */\r\n defaultDaemonRunId?: string;\r\n /** Physical box pool for capacity snapshots (`forge` | `ghost`). Set via `kynver setup --box-kind`. */\r\n boxKind?: \"ghost\" | \"forge\";\r\n /** Max concurrent workers on this machine. Omit to auto-size from RAM. */\r\n maxConcurrentWorkers?: number;\r\n /** Where maxConcurrentWorkers came from. */\r\n maxConcurrentWorkersSource?: \"setup-auto\" | \"setup-flag\" | \"operator\";\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n perWorkerMemBytes?: number;\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n memReserveBytes?: number;\r\n /** @internal Advanced tuning \u2014 not required for setup. */\r\n memUtilization?: number;\r\n}\r\n\r\nconst CONFIG_DIR = path.join(homedir(), \".kynver\");\r\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\r\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, \"credentials\");\r\n\r\ninterface KynverCredentialsFile {\r\n apiKey?: string;\r\n /** Scoped `krc1.*` runner token for AgentOS by-id callbacks. */\r\n runnerToken?: string;\r\n runnerTokenAgentOsId?: string;\r\n}\r\n\r\nexport function loadUserConfig(): KynverUserConfig {\r\n if (!existsSync(CONFIG_FILE)) return {};\r\n try {\r\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf8\")) as KynverUserConfig;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function saveUserConfig(config: KynverUserConfig): void {\r\n mkdirSync(CONFIG_DIR, { recursive: true });\r\n writeFileSync(CONFIG_FILE, `${JSON.stringify(normalizeConfigPaths(config), null, 2)}\\n`, { mode: 0o600 });\r\n}\r\n\r\n/** Persist path fields with `~` instead of absolute home directories. */\r\nexport function normalizeConfigPaths(config: KynverUserConfig): KynverUserConfig {\r\n return {\r\n ...config,\r\n ...(config.harnessRoot?.trim() ? { harnessRoot: redactHomePath(config.harnessRoot.trim()) } : {}),\r\n ...(config.defaultRepo?.trim() ? { defaultRepo: redactHomePath(config.defaultRepo.trim()) } : {}),\r\n };\r\n}\r\n\r\n/** Values for setup output (never emit `/home/<user>/\u2026`). */\r\nexport function presentUserConfig(config: KynverUserConfig): KynverUserConfig {\r\n return normalizeConfigPaths(config);\r\n}\r\n\r\nfunction inferSetupFields(\r\n existing: KynverUserConfig,\r\n args: Record<string, string | boolean>,\r\n): Partial<KynverUserConfig> {\r\n const creds = loadCredentialsFile();\r\n const apiBaseUrl =\r\n (typeof args.apiBaseUrl === \"string\" ? args.apiBaseUrl : undefined) ||\r\n existing.apiBaseUrl?.trim() ||\r\n process.env.KYNVER_API_URL?.trim() ||\r\n process.env.KYNVER_CRON_FIRE_BASE_URL?.trim() ||\r\n process.env.OPENCLAW_CRON_FIRE_BASE_URL?.trim();\r\n const agentOsId =\r\n (typeof args.agentOsId === \"string\" ? args.agentOsId : undefined) ||\r\n existing.agentOsId?.trim() ||\r\n process.env.KYNVER_AGENT_OS_ID?.trim() ||\r\n (creds.runnerToken?.trim().startsWith(\"krc1.\") ? creds.runnerTokenAgentOsId?.trim() : undefined);\r\n const explicitRepo =\r\n typeof args.repo === \"string\"\r\n ? args.repo\r\n : args.discoverRepo === true || args.discoverRepo === \"true\"\r\n ? discoverDefaultRepo()?.repo\r\n : undefined;\r\n const defaultRepo =\r\n explicitRepo ||\r\n existing.defaultRepo?.trim() ||\r\n process.env.KYNVER_DEFAULT_REPO?.trim() ||\r\n process.env.KYNVER_HARNESS_REPO?.trim() ||\r\n discoverDefaultRepo()?.repo;\r\n const harnessRoot =\r\n (typeof args.harnessRoot === \"string\" ? args.harnessRoot : undefined) ||\r\n existing.harnessRoot?.trim() ||\r\n process.env.KYNVER_HARNESS_ROOT?.trim() ||\r\n process.env.OPUS_HARNESS_ROOT?.trim();\r\n\r\n return {\r\n ...(apiBaseUrl ? { apiBaseUrl: trimTrailingSlash(apiBaseUrl) } : {}),\r\n ...(agentOsId ? { agentOsId } : {}),\r\n ...(defaultRepo ? { defaultRepo } : {}),\r\n ...(harnessRoot ? { harnessRoot } : {}),\r\n ...(typeof args.agentOsSlug === \"string\"\r\n ? { agentOsSlug: args.agentOsSlug }\r\n : existing.agentOsSlug\r\n ? { agentOsSlug: existing.agentOsSlug }\r\n : {}),\r\n };\r\n}\r\n\r\nconst SETUP_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;\r\nconst SETUP_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;\r\nconst SETUP_MEM_UTILIZATION = 0.85;\r\nconst SETUP_AUTO_MAX_WORKERS_CEILING = 64;\r\n\r\nfunction normalizeBoxKind(raw: unknown): \"ghost\" | \"forge\" | undefined {\r\n const kind = String(raw ?? \"\").trim().toLowerCase();\r\n if (!kind) return undefined;\r\n if (kind === \"ghost\" || kind.includes(\"ghost\") || kind.includes(\"openclaw\")) return \"ghost\";\r\n if (kind === \"forge\" || kind.includes(\"forge\")) return \"forge\";\r\n return undefined;\r\n}\r\n\r\nexport function computeSetupAutoMaxWorkers(totalMemBytes: number): number {\r\n const budgetBytes = Math.max(0, Math.floor(totalMemBytes * SETUP_MEM_UTILIZATION) - SETUP_MEM_RESERVE_BYTES);\r\n const raw = Math.max(1, Math.floor(budgetBytes / SETUP_PER_WORKER_MEM_BYTES));\r\n return Math.min(raw, SETUP_AUTO_MAX_WORKERS_CEILING);\r\n}\r\n\r\nexport function resolveSetupWorkerConfig(\r\n existing: KynverUserConfig,\r\n args: Record<string, string | boolean>,\r\n totalMemBytes = totalmem(),\r\n): Pick<KynverUserConfig, \"maxConcurrentWorkers\" | \"maxConcurrentWorkersSource\" | \"boxKind\"> {\r\n const maxWorkersRaw =\r\n typeof args.maxWorkers === \"string\"\r\n ? args.maxWorkers\r\n : typeof args.maxConcurrentWorkers === \"string\"\r\n ? args.maxConcurrentWorkers\r\n : undefined;\r\n const explicitBoxKindArg =\r\n typeof args.boxKind === \"string\"\r\n ? args.boxKind\r\n : typeof args[\"box-kind\"] === \"string\"\r\n ? String(args[\"box-kind\"])\r\n : undefined;\r\n const boxKind = resolveBoxIdentity(process.env, {\r\n ...existing,\r\n ...(explicitBoxKindArg ? { boxKind: normalizeWorkerPoolBoxKind(explicitBoxKindArg) } : {}),\r\n }).boxKind;\r\n const diskGate = observeRunnerDiskGate({\r\n diskPath: typeof args.diskPath === \"string\" ? args.diskPath : \"/\",\r\n });\r\n const capRecommendation = recommendSetupWorkerCap({\r\n totalMemBytes,\r\n diskPath: diskGate.path,\r\n diskGateOk: diskGate.ok,\r\n diskFreeBytes: diskGate.freeBytes,\r\n config: existing,\r\n });\r\n if (maxWorkersRaw) {\r\n return {\r\n maxConcurrentWorkers: Math.max(1, Math.floor(Number(maxWorkersRaw))),\r\n maxConcurrentWorkersSource: \"setup-flag\",\r\n boxKind,\r\n };\r\n }\r\n if (existing.maxConcurrentWorkers !== undefined && existing.maxConcurrentWorkers !== null) {\r\n return {\r\n maxConcurrentWorkers: Math.max(1, Math.floor(Number(existing.maxConcurrentWorkers))),\r\n maxConcurrentWorkersSource: existing.maxConcurrentWorkersSource ?? \"operator\",\r\n boxKind,\r\n };\r\n }\r\n return {\r\n maxConcurrentWorkers: capRecommendation.recommendedMaxWorkers,\r\n maxConcurrentWorkersSource: \"setup-auto\",\r\n boxKind,\r\n };\r\n}\r\n\r\nfunction loadCredentialsFile(): KynverCredentialsFile {\r\n if (!existsSync(CREDENTIALS_FILE)) return {};\r\n try {\r\n return JSON.parse(readFileSync(CREDENTIALS_FILE, \"utf8\")) as KynverCredentialsFile;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction saveCredentialsFile(parsed: KynverCredentialsFile): void {\r\n mkdirSync(CONFIG_DIR, { recursive: true });\r\n writeFileSync(CREDENTIALS_FILE, `${JSON.stringify(parsed, null, 2)}\\n`, { mode: 0o600 });\r\n}\r\n\r\nexport function loadApiKey(): string | undefined {\r\n if (process.env.KYNVER_API_KEY) return process.env.KYNVER_API_KEY;\r\n return loadCredentialsFile().apiKey;\r\n}\r\n\r\nexport function saveApiKey(apiKey: string): void {\r\n saveCredentialsFile({ ...loadCredentialsFile(), apiKey });\r\n}\r\n\r\nexport function loadRunnerToken(agentOsId?: string): string | undefined {\r\n const envToken = process.env.KYNVER_RUNNER_TOKEN?.trim();\r\n if (envToken) return envToken;\r\n\r\n const creds = loadCredentialsFile();\r\n if (!creds.runnerToken) return undefined;\r\n if (agentOsId && creds.runnerTokenAgentOsId && creds.runnerTokenAgentOsId !== agentOsId) {\r\n return undefined;\r\n }\r\n return creds.runnerToken;\r\n}\r\n\r\nexport function saveRunnerToken(agentOsId: string, token: string): void {\r\n saveCredentialsFile({\r\n ...loadCredentialsFile(),\r\n runnerToken: token,\r\n runnerTokenAgentOsId: agentOsId,\r\n });\r\n}\r\n\r\nexport function resolveBaseUrl(argsBaseUrl?: string): string {\r\n const baseUrl = resolveConfiguredBaseUrl(argsBaseUrl);\r\n if (!baseUrl) failConfig(\"requires --base-url, KYNVER_API_URL, KYNVER_CRON_FIRE_BASE_URL, or ~/.kynver/config.json apiBaseUrl\");\r\n return baseUrl;\r\n}\r\n\r\nfunction resolveConfiguredBaseUrl(argsBaseUrl?: string): string | undefined {\r\n const baseUrl =\r\n argsBaseUrl ||\r\n process.env.KYNVER_API_URL ||\r\n process.env.KYNVER_CRON_FIRE_BASE_URL ||\r\n process.env.OPENCLAW_CRON_FIRE_BASE_URL ||\r\n loadUserConfig().apiBaseUrl;\r\n return baseUrl ? trimTrailingSlash(String(baseUrl)) : undefined;\r\n}\r\n\r\nfunction resolveConfiguredCallbackSecret(argsSecret?: string, agentOsId?: string): string | undefined {\r\n const scoped =\r\n argsSecret ||\r\n loadRunnerToken(agentOsId) ||\r\n (agentOsId ? undefined : loadRunnerToken(loadUserConfig().agentOsId));\r\n if (scoped) return String(scoped);\r\n\r\n const globalSecret =\r\n process.env.KYNVER_RUNTIME_SECRET ||\r\n process.env.KYNVER_CRON_SECRET ||\r\n process.env.OPENCLAW_CRON_SECRET;\r\n if (globalSecret) {\r\n console.warn(\r\n \"[kynver] using deployment-level callback secret; run `kynver runner credential --agent-os-id <id>` for a scoped token\",\r\n );\r\n return String(globalSecret);\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nexport function resolveCallbackSecret(argsSecret?: string, agentOsId?: string): string {\r\n const configured = resolveConfiguredCallbackSecret(argsSecret, agentOsId);\r\n if (configured) return configured;\r\n\r\n failConfig(\r\n \"requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET\",\r\n );\r\n}\r\n\r\nexport async function resolveCallbackSecretWithMint(\r\n argsSecret?: string,\r\n agentOsId?: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<string> {\r\n const configured = resolveConfiguredCallbackSecret(argsSecret, agentOsId);\r\n if (configured) return configured;\r\n\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (apiKey && agentOsId && baseUrl) {\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n saveRunnerToken(agentOsId, token);\r\n return token;\r\n } catch (error) {\r\n failConfig(`runner credential mint failed: ${(error as Error).message}`);\r\n }\r\n }\r\n\r\n failConfig(\r\n \"requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET\",\r\n );\r\n}\r\n\r\n/**\r\n * Force-mint a fresh scoped runner token for `agentOsId`, bypassing any cached\r\n * or env token. Recovery path for a callback that 401s because the configured\r\n * token is revoked, expired, or scoped to a *different* workspace (the\r\n * self-linked repair case). Requires an API key + base URL to mint; returns\r\n * `null` when a fresh token cannot be obtained, so the caller degrades to a\r\n * structural blocker instead of papering the worker over as done.\r\n */\r\nexport async function refreshRunnerToken(\r\n agentOsId: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<string | null> {\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (!apiKey || !agentOsId || !baseUrl) return null;\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n saveRunnerToken(agentOsId, token);\r\n return token;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport async function refreshRunnerTokenForAuthFailure(\r\n rejectedSecret: string,\r\n agentOsId: string,\r\n opts?: { baseUrl?: string },\r\n): Promise<{ ok: true; token: string } | { ok: false; reason: string }> {\r\n const apiKey = loadApiKey();\r\n const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);\r\n if (!apiKey) return { ok: false, reason: \"KYNVER_API_KEY is required to refresh a rejected runner token\" };\r\n if (!agentOsId) return { ok: false, reason: \"agentOsId is required to refresh a rejected runner token\" };\r\n if (!baseUrl) return { ok: false, reason: \"KYNVER_API_URL or --base-url is required to refresh a rejected runner token\" };\r\n\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });\r\n if (token && token !== rejectedSecret) {\r\n saveRunnerToken(agentOsId, token);\r\n return { ok: true, token };\r\n }\r\n return { ok: false, reason: \"runner credential refresh returned the rejected token\" };\r\n } catch (error) {\r\n return { ok: false, reason: (error as Error).message };\r\n }\r\n}\r\n\r\nexport async function fetchRunnerCredential(\r\n agentOsId: string,\r\n opts?: { baseUrl?: string; apiKey?: string },\r\n): Promise<string> {\r\n const apiKey = opts?.apiKey || loadApiKey();\r\n if (!apiKey) throw new Error(\"API key required \u2014 run `kynver login` first\");\r\n\r\n const base = resolveBaseUrl(opts?.baseUrl);\r\n const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/runner-credentials`;\r\n const res = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({}),\r\n });\r\n\r\n const text = await res.text();\r\n let parsed: { token?: string; error?: string } | null = null;\r\n try {\r\n parsed = JSON.parse(text) as { token?: string; error?: string };\r\n } catch {\r\n parsed = null;\r\n }\r\n if (!res.ok || !parsed?.token) {\r\n throw new Error(\r\n `runner credential mint failed (${res.status}): ${parsed?.error ?? text.slice(0, 200)}`,\r\n );\r\n }\r\n return parsed.token;\r\n}\r\n\r\nexport async function mintRunnerCredential(args: Record<string, string | boolean>): Promise<void> {\r\n const agentOsId =\r\n (args.agentOsId ? String(args.agentOsId) : loadUserConfig().agentOsId) || \"\";\r\n if (!agentOsId) failConfig(\"runner credential requires --agent-os-id or agentOsId in ~/.kynver/config.json\");\r\n\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, {\r\n baseUrl: args.baseUrl ? String(args.baseUrl) : undefined,\r\n });\r\n saveRunnerToken(agentOsId, token);\r\n console.log(\r\n JSON.stringify(\r\n {\r\n ok: true,\r\n agentOsId,\r\n credentialsPath: displayUserPath(CREDENTIALS_FILE),\r\n tokenPrefix: `${token.slice(0, 12)}\u2026`,\r\n note: \"Scoped runner token saved; callbacks use X-Kynver-Runner-Token.\",\r\n },\r\n null,\r\n 2,\r\n ),\r\n );\r\n } catch (err) {\r\n console.error(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction failConfig(message: string): never {\r\n console.error(message);\r\n process.exit(1);\r\n}\r\n\r\nexport function parseArgs(argv: string[]): Record<string, string | boolean> {\r\n const args: Record<string, string | boolean> = {};\r\n for (let i = 0; i < argv.length; i++) {\r\n const item = argv[i];\r\n if (!item.startsWith(\"--\")) continue;\r\n const key = item.slice(2).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\r\n const next = argv[i + 1];\r\n if (!next || next.startsWith(\"--\")) args[key] = true;\r\n else {\r\n args[key] = next;\r\n i++;\r\n }\r\n }\r\n return args;\r\n}\r\n\r\nexport async function runSetup(args: Record<string, string | boolean>): Promise<void> {\r\n const existing = loadUserConfig();\r\n const diskGate = observeRunnerDiskGate({\r\n diskPath: typeof args.diskPath === \"string\" ? args.diskPath : \"/\",\r\n });\r\n const capRecommendation = recommendSetupWorkerCap({\r\n totalMemBytes: os.totalmem(),\r\n diskPath: diskGate.path,\r\n diskGateOk: diskGate.ok,\r\n diskFreeBytes: diskGate.freeBytes,\r\n config: existing,\r\n });\r\n const workerConfig = resolveSetupWorkerConfig(existing, args);\r\n const config: KynverUserConfig = normalizeConfigPaths({\r\n ...existing,\r\n ...inferSetupFields(existing, args),\r\n ...workerConfig,\r\n workerProvider:\r\n typeof args.provider === \"string\"\r\n ? args.provider\r\n : existing.workerProvider || \"cursor\",\r\n });\r\n saveUserConfig(config);\r\n const boxIdentity = resolveBoxIdentity(process.env, config);\r\n\r\n let runnerCredentialNote: string | undefined;\r\n const apiKey = loadApiKey();\r\n const agentOsId = config.agentOsId;\r\n if (apiKey && agentOsId) {\r\n try {\r\n const token = await fetchRunnerCredential(agentOsId, {\r\n baseUrl: typeof args.apiBaseUrl === \"string\" ? args.apiBaseUrl : config.apiBaseUrl,\r\n apiKey,\r\n });\r\n saveRunnerToken(agentOsId, token);\r\n runnerCredentialNote = \"Scoped runner token minted and saved to ~/.kynver/credentials.\";\r\n } catch {\r\n runnerCredentialNote =\r\n \"Runner token not minted (server offline or master secret unset). Run `kynver runner credential` after deploy.\";\r\n }\r\n }\r\n\r\n console.log(\r\n JSON.stringify(\r\n {\r\n ok: true,\r\n configPath: displayUserPath(CONFIG_FILE),\r\n config: presentUserConfig(config),\r\n boxKind: config.boxKind,\r\n boxKindSource: boxIdentity.source,\r\n workerCapRecommendation: capRecommendation,\r\n ...(boxIdentity.warnings.length ? { boxIdentityWarnings: boxIdentity.warnings } : {}),\r\n note:\r\n runnerCredentialNote ??\r\n \"boxKind and maxConcurrentWorkers persisted; override with --box-kind and --max-workers. Run `kynver login` + `kynver runner credential` for scoped callbacks.\",\r\n },\r\n null,\r\n 2,\r\n ),\r\n );\r\n}\r\n\r\nexport async function runLogin(args: Record<string, string | boolean>): Promise<void> {\r\n const apiKey = typeof args.apiKey === \"string\" ? args.apiKey : process.env.KYNVER_API_KEY;\r\n if (apiKey) {\r\n saveApiKey(apiKey);\r\n console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));\r\n return;\r\n }\r\n // No key provided \u2014 run the browser \"authorize this machine\" device flow.\r\n const { runDeviceLogin } = await import(\"./device-login.js\");\r\n const result = await runDeviceLogin(args);\r\n if (!result.ok) process.exit(1);\r\n console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));\r\n}\r\n", "import { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { loadUserConfig } from \"./config.js\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\nconst LEGACY_ROOT = path.join(homedir(), \".openclaw\", \"harness\");\r\n\r\nconst HARNESS_LAYOUT_DIR_NAMES = new Set([\"runs\", \"worktrees\"]);\r\n\r\n/**\r\n * Canonical harness root: the directory that contains `runs/` and `worktrees/`.\r\n * Strips mistaken trailing layout segments (e.g. env set to `.../harness/runs`).\r\n * Server mirror: agent-os.harness-root.ts\r\n */\r\nexport function normalizeHarnessRoot(root: string): string {\r\n let resolved = path.resolve(resolveUserPath(root.trim()));\r\n while (HARNESS_LAYOUT_DIR_NAMES.has(path.basename(resolved))) {\r\n resolved = path.dirname(resolved);\r\n }\r\n return resolved;\r\n}\r\n\r\n/** Canonical harness root for CLI/workers. */\r\nexport function resolveHarnessRoot(): string {\r\n const env = process.env.KYNVER_HARNESS_ROOT || process.env.OPUS_HARNESS_ROOT;\r\n if (env) return normalizeHarnessRoot(env);\r\n const configured = loadUserConfig().harnessRoot?.trim();\r\n if (configured) return normalizeHarnessRoot(configured);\r\n const kynverRoot = path.join(homedir(), \".kynver\", \"harness\");\r\n if (existsSync(kynverRoot)) return kynverRoot;\r\n if (existsSync(LEGACY_ROOT)) return LEGACY_ROOT;\r\n return kynverRoot;\r\n}\r\n\r\nexport function harnessRunsDir(harnessRoot: string): string {\r\n return path.join(normalizeHarnessRoot(harnessRoot), \"runs\");\r\n}\r\n\r\nexport function harnessWorktreesDir(harnessRoot: string): string {\r\n return path.join(normalizeHarnessRoot(harnessRoot), \"worktrees\");\r\n}\r\n\r\nexport function getHarnessPaths() {\r\n const harnessRoot = resolveHarnessRoot();\r\n return {\r\n harnessRoot,\r\n runsDir: harnessRunsDir(harnessRoot),\r\n worktreesDir: harnessWorktreesDir(harnessRoot),\r\n };\r\n}\r\n\r\nexport function runDir(runsDir: string, id: string): string {\r\n return path.join(runsDir, safeSlug(id));\r\n}\r\n", "import path from \"node:path\";\r\nimport { resolveUserPath } from \"./path-values.js\";\r\nimport { normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport {\r\n type CleanupAction,\r\n type CleanupCandidate,\r\n type CleanupSkipReason,\r\n type HarnessCleanupOptions,\r\n type HarnessCleanupSummary,\r\n} from \"./cleanup-types.js\";\r\nimport {\r\n skipBuildCacheRemoval,\r\n skipDependencyCacheRemoval,\r\n skipWorktreeRemoval,\r\n type WorktreeGuardSkip,\r\n} from \"./cleanup-guards.js\";\r\nimport { collectPreservedLivePaths } from \"./cleanup-evidence.js\";\r\nimport {\r\n scanStaleRunDirectoryCandidates,\r\n skipRunDirectoryRemoval,\r\n} from \"./cleanup-run-directory.js\";\r\nimport {\r\n isHarnessBuildCachePath,\r\n isHarnessNextCachePath,\r\n isHarnessNodeModulesPath,\r\n removeBuildCache,\r\n removeNextCache,\r\n removeNodeModules,\r\n removeRunDirectory,\r\n removeWorktree,\r\n} from \"./cleanup-execute.js\";\r\nimport { scanBuildCacheCandidates, scanWorktreeCandidates } from \"./cleanup-scan.js\";\r\nimport { scanDependencyCacheCandidates } from \"./cleanup-dependency-scan.js\";\r\nimport { scanDuplicateWorktreeCandidates } from \"./cleanup-duplicate-worktrees.js\";\r\nimport { buildWorktreeIndexAt, type IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { finalizeStaleRuns } from \"./finalize.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport { resolveHarnessRetention, resolvePipelineHarnessRetention } from \"./cleanup-retention-config.js\";\r\nimport { assessOrphanWorktreeSafety } from \"./cleanup-orphan-safety.js\";\r\nimport { harnessStorageSnapshot } from \"./harness-storage-snapshot.js\";\r\nimport { resolveHarnessScanRoots } from \"./cleanup-harness-roots.js\";\r\nimport { collectActiveWorktreeGuards } from \"./cleanup-active-worktrees.js\";\r\nimport { applyDiskPressureToRetention, observeCleanupDiskPressure } from \"./cleanup-disk-pressure.js\";\r\nimport { emitCleanupProgress } from \"./cleanup-progress.js\";\r\nimport { CleanupGitRevCache } from \"./cleanup-git-rev-cache.js\";\r\nimport { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport { CleanupRunTerminalCache } from \"./cleanup-run-terminal-cache.js\";\r\nimport { buildCleanupCompactSummary } from \"./cleanup-summary.js\";\r\n\r\nfunction resolvePaths(options: HarnessCleanupOptions = {}) {\r\n const harnessRoot = options.harnessRoot\r\n ? normalizeHarnessRoot(options.harnessRoot)\r\n : resolveHarnessRoot();\r\n const scanRoots = resolveHarnessScanRoots({ harnessRoot });\r\n const now = options.now ?? Date.now();\r\n return { harnessRoot, scanRoots, now };\r\n}\r\n\r\nfunction normalizeGuardSkip(skip: WorktreeGuardSkip): { reason: CleanupSkipReason; detail?: string } {\r\n if (typeof skip === \"string\") return { reason: skip };\r\n return skip;\r\n}\r\n\r\nfunction recordSkip(\r\n skips: HarnessCleanupSummary[\"skips\"],\r\n pathValue: string,\r\n reason: CleanupSkipReason,\r\n detail?: string,\r\n): void {\r\n skips.push({ path: pathValue, reason, ...(detail ? { detail } : {}) });\r\n}\r\n\r\nfunction attachCandidateBytes(\r\n candidate: CleanupCandidate,\r\n accountBytes: boolean,\r\n byteEntryCap: number,\r\n): CleanupCandidate {\r\n if (!accountBytes || candidate.bytes != null) return candidate;\r\n return { ...candidate, bytes: directorySizeBytes(candidate.path, byteEntryCap) };\r\n}\r\n\r\nfunction tallySkipReasons(\r\n actions: CleanupAction[],\r\n skips: HarnessCleanupSummary[\"skips\"],\r\n): Partial<Record<CleanupSkipReason, number>> {\r\n const counts: Partial<Record<CleanupSkipReason, number>> = {};\r\n for (const skip of skips) {\r\n counts[skip.reason] = (counts[skip.reason] ?? 0) + 1;\r\n }\r\n for (const action of actions) {\r\n if (action.skipReason) {\r\n counts[action.skipReason] = (counts[action.skipReason] ?? 0) + 1;\r\n }\r\n }\r\n return counts;\r\n}\r\n\r\nfunction removeDependencyCacheAction(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n if (candidate.kind === \"remove_next_cache\") return removeNextCache(candidate, execute);\r\n return removeNodeModules(candidate, execute);\r\n}\r\n\r\nfunction pathGuardForDependencyCache(\r\n candidate: CleanupCandidate,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n if (candidate.kind === \"remove_next_cache\") {\r\n return isHarnessNextCachePath(candidate.path, harnessRoot, worktreesDir);\r\n }\r\n return isHarnessNodeModulesPath(candidate.path, harnessRoot, worktreesDir);\r\n}\r\n\r\nfunction mergeWorktreeIndexes(scanRoots: string[]): Map<string, IndexedWorktree> {\r\n const merged = new Map<string, IndexedWorktree>();\r\n for (const root of scanRoots) {\r\n for (const [key, value] of buildWorktreeIndexAt(root)) merged.set(key, value);\r\n }\r\n return merged;\r\n}\r\n\r\nfunction worktreePathForCandidate(\r\n candidate: CleanupCandidate,\r\n worktreesDir: string,\r\n): string {\r\n if (candidate.runId && candidate.worker) {\r\n return path.join(worktreesDir, candidate.runId, candidate.worker);\r\n }\r\n return path.resolve(candidate.path, \"..\");\r\n}\r\n\r\nexport function runHarnessCleanup(options: HarnessCleanupOptions = {}): HarnessCleanupSummary {\r\n let retention = resolveHarnessRetention(options);\r\n const diskPressure = observeCleanupDiskPressure();\r\n retention = applyDiskPressureToRetention(retention, diskPressure);\r\n\r\n const paths = resolvePaths(options);\r\n emitCleanupProgress(\"scan\", `${paths.scanRoots.length} harness root(s)`);\r\n const activeGuards = collectActiveWorktreeGuards(paths.scanRoots, paths.now);\r\n\r\n const finalizedRuns = retention.finalizeStaleRuns\r\n ? finalizeStaleRuns().map((f) => ({ runId: f.runId, from: f.from, to: f.to }))\r\n : [];\r\n if (finalizedRuns.length > 0) {\r\n emitCleanupProgress(\"finalize\", `${finalizedRuns.length} stale run(s) marked terminal`);\r\n }\r\n\r\n emitCleanupProgress(\"index\", \"building worktree index\");\r\n const index = mergeWorktreeIndexes(paths.scanRoots);\r\n emitCleanupProgress(\"index\", `${index.size} indexed worktree(s)`);\r\n const liveness = {\r\n runTerminalCache: new CleanupRunTerminalCache(),\r\n gitStatusCache: new CleanupGitStatusCache(),\r\n gitRevCache: new CleanupGitRevCache(),\r\n };\r\n\r\n const skips: HarnessCleanupSummary[\"skips\"] = [];\r\n const actions: CleanupAction[] = [];\r\n const processedPaths = new Set<string>();\r\n const maxActions = retention.maxActionsPerSweep;\r\n\r\n const atSweepCap = (): boolean => actions.length >= maxActions;\r\n\r\n for (const harnessRoot of paths.scanRoots) {\r\n if (atSweepCap()) break;\r\n emitCleanupProgress(\"root\", harnessRoot);\r\n const worktreesDir = path.join(harnessRoot, \"worktrees\");\r\n const scanOpts = {\r\n harnessRoot,\r\n worktreesDir,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n runIdFilter: retention.runIdFilter,\r\n index,\r\n now: paths.now,\r\n };\r\n\r\n const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);\r\n emitCleanupProgress(\"dependency\", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);\r\n let dependencyProcessed = 0;\r\n for (const raw of dependencyCandidates) {\r\n if (atSweepCap()) break;\r\n dependencyProcessed += 1;\r\n if (dependencyProcessed % 50 === 0) {\r\n emitCleanupProgress(\"dependency\", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);\r\n }\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n\r\n const pathSkip = pathGuardForDependencyCache(candidate, harnessRoot, worktreesDir);\r\n if (pathSkip) {\r\n recordSkip(skips, candidate.path, pathSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: pathSkip });\r\n continue;\r\n }\r\n const worktreePath = worktreePathForCandidate(candidate, worktreesDir);\r\n const indexed = index.get(path.resolve(worktreePath)) ?? null;\r\n const guardReason = skipDependencyCacheRemoval({\r\n indexed,\r\n includeOrphans: true,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n ageMs: candidate.ageMs,\r\n worktreePath,\r\n activeWorktreePaths: activeGuards.activeWorktreePaths,\r\n diskPressure: retention.diskPressure,\r\n gitStatusCache: liveness.gitStatusCache,\r\n });\r\n if (guardReason) {\r\n recordSkip(skips, candidate.path, guardReason);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeDependencyCacheAction(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n for (const raw of scanBuildCacheCandidates(scanOpts)) {\r\n if (atSweepCap()) break;\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n\r\n const pathSkip = isHarnessBuildCachePath(candidate.path, harnessRoot, worktreesDir);\r\n if (pathSkip) {\r\n recordSkip(skips, candidate.path, pathSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: pathSkip });\r\n continue;\r\n }\r\n const worktreePath = worktreePathForCandidate(candidate, worktreesDir);\r\n const indexed = index.get(path.resolve(worktreePath)) ?? null;\r\n const guardReason = skipBuildCacheRemoval({\r\n indexed,\r\n includeOrphans: true,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n ageMs: candidate.ageMs,\r\n worktreePath,\r\n activeWorktreePaths: activeGuards.activeWorktreePaths,\r\n diskPressure: retention.diskPressure,\r\n gitStatusCache: liveness.gitStatusCache,\r\n });\r\n if (guardReason) {\r\n recordSkip(skips, candidate.path, guardReason);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeBuildCache(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n const worktreeCandidates = [\r\n ...scanWorktreeCandidates(scanOpts),\r\n ...scanDuplicateWorktreeCandidates(scanOpts),\r\n ];\r\n emitCleanupProgress(\"worktrees\", `${worktreeCandidates.length} candidate(s) at ${harnessRoot}`);\r\n const worktreeSeen = new Set<string>();\r\n let worktreeProcessed = 0;\r\n for (const raw of worktreeCandidates) {\r\n if (atSweepCap()) break;\r\n worktreeProcessed += 1;\r\n if (worktreeProcessed % 50 === 0) {\r\n emitCleanupProgress(\"worktrees\", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);\r\n }\r\n const resolved = path.resolve(raw.path);\r\n if (worktreeSeen.has(resolved)) continue;\r\n worktreeSeen.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n const indexed = index.get(path.resolve(candidate.path)) ?? null;\r\n const orphanSafety = indexed\r\n ? null\r\n : assessOrphanWorktreeSafety({\r\n worktreePath: candidate.path,\r\n harnessRoot,\r\n runId: candidate.runId,\r\n workerName: candidate.worker,\r\n now: paths.now,\r\n });\r\n const guardSkip = skipWorktreeRemoval({\r\n indexed,\r\n worktreePath: path.resolve(candidate.path),\r\n includeOrphans: retention.includeOrphans,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n terminalWorktreesAgeMs: retention.terminalWorktreesAgeMs,\r\n ageMs: candidate.ageMs,\r\n orphanSafety,\r\n worktreeRemovalGuard: options.worktreeRemovalGuard,\r\n liveness,\r\n });\r\n if (guardSkip) {\r\n const { reason: guardReason, detail: guardDetail } = normalizeGuardSkip(guardSkip);\r\n recordSkip(skips, candidate.path, guardReason, guardDetail);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: guardReason });\r\n continue;\r\n }\r\n actions.push(\r\n removeWorktree(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n\r\n if (!atSweepCap() && retention.runDirectoriesAgeMs >= 0) {\r\n for (const raw of scanStaleRunDirectoryCandidates({\r\n harnessRoot,\r\n worktreesDir,\r\n runDirectoriesAgeMs: retention.runDirectoriesAgeMs,\r\n runIdFilter: retention.runIdFilter,\r\n activeGuards,\r\n now: paths.now,\r\n })) {\r\n if (atSweepCap()) break;\r\n const resolved = path.resolve(raw.path);\r\n if (processedPaths.has(resolved)) continue;\r\n processedPaths.add(resolved);\r\n const candidate: CleanupCandidate = { ...raw, path: resolved };\r\n const runId = candidate.runId ?? path.basename(resolved);\r\n const dirSkip = skipRunDirectoryRemoval({\r\n harnessRoot,\r\n runId,\r\n runPath: resolved,\r\n ageMs: candidate.ageMs,\r\n runDirectoriesAgeMs: retention.runDirectoriesAgeMs,\r\n activeGuards,\r\n });\r\n if (dirSkip) {\r\n recordSkip(skips, candidate.path, dirSkip);\r\n actions.push({ ...candidate, executed: false, skipped: true, skipReason: dirSkip });\r\n continue;\r\n }\r\n actions.push(\r\n removeRunDirectory(\r\n attachCandidateBytes(candidate, retention.accountBytes, retention.byteAccountingEntryCap),\r\n retention.execute,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n\r\n let candidateBytes = 0;\r\n let removedRunDirectories = 0;\r\n let reclaimableBytes = 0;\r\n let removedBytes = 0;\r\n let removedPaths = 0;\r\n let skippedPaths = 0;\r\n for (const action of actions) {\r\n if (action.bytes) candidateBytes += action.bytes;\r\n if (!action.skipped && !action.executed && action.bytes) reclaimableBytes += action.bytes;\r\n if (action.executed) {\r\n removedPaths += 1;\r\n removedBytes += action.bytes ?? 0;\r\n if (action.kind === \"remove_run_directory\") removedRunDirectories += 1;\r\n } else if (action.skipped) {\r\n skippedPaths += 1;\r\n if (action.skipReason === \"dry_run\" && action.bytes) reclaimableBytes += action.bytes;\r\n }\r\n }\r\n\r\n const storage = retention.accountBytes\r\n ? harnessStorageSnapshot({\r\n harnessRoot: paths.harnessRoot,\r\n now: paths.now,\r\n perRunEntryCap: retention.storagePerRunEntryCap,\r\n })\r\n : undefined;\r\n emitCleanupProgress(\r\n \"complete\",\r\n `${actions.length} action(s), ${skippedPaths} skipped, ${removedPaths} removed`,\r\n );\r\n\r\n const preservedLivePaths = collectPreservedLivePaths(actions, skips);\r\n const compactSummary = buildCleanupCompactSummary({\r\n harnessRoot: paths.harnessRoot,\r\n scanRoots: paths.scanRoots,\r\n dryRun: !retention.execute,\r\n execute: retention.execute,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n diskPressure: retention.diskPressure,\r\n diskGate: retention.diskGate\r\n ? {\r\n ok: retention.diskGate.ok,\r\n path: retention.diskGate.path,\r\n freeBytes: retention.diskGate.freeBytes,\r\n usedPercent: retention.diskGate.usedPercent,\r\n reason: retention.diskGate.reason,\r\n }\r\n : undefined,\r\n scannedAt: new Date(paths.now).toISOString(),\r\n finalizedRuns,\r\n actions,\r\n skips,\r\n totals: {\r\n candidateBytes,\r\n reclaimableBytes,\r\n removedBytes,\r\n removedPaths,\r\n skippedPaths,\r\n skipReasons: tallySkipReasons(actions, skips),\r\n },\r\n ...(storage ? { storage } : {}),\r\n ...(preservedLivePaths.length > 0 ? { preservedLivePaths } : {}),\r\n ...(removedRunDirectories > 0 ? { removedRunDirectories } : {}),\r\n });\r\n\r\n return {\r\n harnessRoot: paths.harnessRoot,\r\n scanRoots: paths.scanRoots,\r\n dryRun: !retention.execute,\r\n execute: retention.execute,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n diskPressure: retention.diskPressure,\r\n diskGate: retention.diskGate\r\n ? {\r\n ok: retention.diskGate.ok,\r\n path: retention.diskGate.path,\r\n freeBytes: retention.diskGate.freeBytes,\r\n usedPercent: retention.diskGate.usedPercent,\r\n reason: retention.diskGate.reason,\r\n }\r\n : undefined,\r\n scannedAt: new Date(paths.now).toISOString(),\r\n finalizedRuns,\r\n actions,\r\n skips,\r\n totals: {\r\n candidateBytes,\r\n reclaimableBytes,\r\n removedBytes,\r\n removedPaths,\r\n skippedPaths,\r\n skipReasons: tallySkipReasons(actions, skips),\r\n },\r\n ...(storage ? { storage } : {}),\r\n ...(preservedLivePaths.length > 0 ? { preservedLivePaths } : {}),\r\n ...(removedRunDirectories > 0 ? { removedRunDirectories } : {}),\r\n compactSummary,\r\n };\r\n}\r\n\r\n/** Pipeline-safe defaults: finalize stale runs, dry-run unless execute env is set. */\r\nexport function runPipelineHarnessCleanup(runId?: string): HarnessCleanupSummary {\r\n const retention = resolvePipelineHarnessRetention(runId);\r\n return runHarnessCleanup({\r\n execute: retention.execute,\r\n finalizeStaleRuns: retention.finalizeStaleRuns,\r\n accountBytes: retention.accountBytes,\r\n nodeModulesAgeMs: retention.nodeModulesAgeMs,\r\n worktreesAgeMs: retention.worktreesAgeMs,\r\n includeOrphans: retention.includeOrphans,\r\n runIdFilter: retention.runIdFilter,\r\n });\r\n}\r\n\r\nexport function isPipelineCleanupEnabled(): boolean {\r\n return process.env.KYNVER_PIPELINE_CLEANUP !== \"0\";\r\n}\r\n", "import path from \"node:path\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupSkipReason, WorktreeRemovalGuardHook } from \"./cleanup-types.js\";\r\nimport { assessWorkerLanding } from \"./landing-gate.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport {\r\n indexedWorktreeHasMaterialChanges,\r\n resolveWorktreeGuardStatus,\r\n} from \"./cleanup-index-status.js\";\r\nimport type { CleanupRunLivenessContext } from \"./cleanup-run-liveness.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport { TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { isRunStaleActive, isWorkerProcessLive, runBlocksWorktreeRemoval } from \"./cleanup-run-liveness.js\";\r\nimport { completionBlockerBlocksWorktreeRemoval } from \"./cleanup-completion-blocker.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport {\r\n isLandedGitAncestry,\r\n isPrOrUnmergedWork,\r\n prUrlFromFinalResult,\r\n} from \"./cleanup-worktree-salvage.js\";\r\n\r\nexport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nexport { isLandedGitAncestry, isPrOrUnmergedWork } from \"./cleanup-worktree-salvage.js\";\r\n\r\nexport interface WorktreeGuardInput {\r\n indexed: IndexedWorktree | null;\r\n /** Resolved worktree directory (required for overlay guards on orphans). */\r\n worktreePath: string;\r\n includeOrphans: boolean;\r\n worktreesAgeMs: number;\r\n /** Shorter age gate for harness runs already marked terminal. */\r\n terminalWorktreesAgeMs: number;\r\n ageMs: number;\r\n /**\r\n * Filesystem-derived skip reason for orphan candidates (computed by\r\n * `assessOrphanWorktreeSafety`). Used only when `indexed` is null.\r\n */\r\n orphanSafety?: CleanupSkipReason | null;\r\n worktreeRemovalGuard?: WorktreeRemovalGuardHook;\r\n liveness?: CleanupRunLivenessContext;\r\n}\r\n\r\nexport type WorktreeGuardSkip = CleanupSkipReason | { reason: CleanupSkipReason; detail?: string };\r\n\r\nfunction effectiveWorktreeAgeMs(input: WorktreeGuardInput): number {\r\n const { indexed, includeOrphans, worktreesAgeMs, terminalWorktreesAgeMs } = input;\r\n if (!indexed) return includeOrphans ? terminalWorktreesAgeMs : worktreesAgeMs;\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n if (input.liveness && isRunStaleActive(indexed, input.liveness)) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n if (\r\n input.liveness &&\r\n isFinishedWorkerStatus(resolveWorktreeGuardStatus(indexed, input.liveness)) &&\r\n !isWorkerProcessLive(indexed)\r\n ) {\r\n return terminalWorktreesAgeMs;\r\n }\r\n return worktreesAgeMs;\r\n}\r\n\r\nexport function skipWorktreeRemoval(input: WorktreeGuardInput): WorktreeGuardSkip | null {\r\n const { indexed, includeOrphans, worktreesAgeMs, ageMs, orphanSafety, worktreeRemovalGuard } =\r\n input;\r\n if (!indexed) {\r\n if (!includeOrphans) return \"orphan_without_flag\";\r\n return orphanSafety ?? null;\r\n }\r\n // `--include-orphans` is the operator opt-in for aggressive cleanup; trust\r\n // the indexed salvage gates below (active_worker, pr_or_unmerged_commits,\r\n // dirty_worktree, landing_blocked) instead of the age-only short-circuit.\r\n const ageThresholdMs = effectiveWorktreeAgeMs(input);\r\n if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return \"worktrees_disabled\";\r\n if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return \"below_age_threshold\";\r\n if (isWorkerProcessLive(indexed)) return \"active_worker\";\r\n if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {\r\n return \"dirty_worktree\";\r\n }\r\n const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);\r\n if (ahead !== null && ahead !== undefined && ahead > 0) return \"pr_or_unmerged_commits\";\r\n const status = resolveWorktreeGuardStatus(indexed, input.liveness);\r\n if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return \"completion_blocked\";\r\n if (runBlocksWorktreeRemoval(indexed, input.liveness)) return \"run_still_active\";\r\n if (!isFinishedWorkerStatus(status)) return \"run_still_active\";\r\n if (isPrOrUnmergedWork(status)) return \"pr_or_unmerged_commits\";\r\n if (materialWorktreeChanges(status.changedFiles).length > 0) return \"dirty_worktree\";\r\n const landing = assessWorkerLanding({\r\n finalResult: status.finalResult,\r\n changedFiles: status.changedFiles,\r\n gitAncestry: status.gitAncestry,\r\n prUrl: prUrlFromFinalResult(status.finalResult),\r\n });\r\n if (landing.blocked) return \"landing_blocked\";\r\n if (worktreeRemovalGuard && input.worktreePath) {\r\n const overlay = worktreeRemovalGuard({\r\n worktreePath: input.worktreePath,\r\n indexed: Boolean(indexed),\r\n runId: indexed?.runId,\r\n worker: indexed?.workerName,\r\n });\r\n if (overlay) {\r\n return overlay.detail ? { reason: overlay.reason, detail: overlay.detail } : overlay.reason;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nexport interface NodeModulesGuardInput {\r\n indexed: IndexedWorktree | null;\r\n includeOrphans: boolean;\r\n nodeModulesAgeMs: number;\r\n ageMs: number;\r\n}\r\n\r\nexport interface DependencyCacheGuardInput extends NodeModulesGuardInput {\r\n worktreePath: string;\r\n activeWorktreePaths: Set<string>;\r\n diskPressure?: boolean;\r\n gitStatusCache?: CleanupGitStatusCache;\r\n}\r\n\r\n/**\r\n * Dependency caches (`node_modules`, `.next`) are safe to drop when the worker\r\n * process is dead and source files remain \u2014 even if the board still shows\r\n * completion/landing/PR blockers. Whole-worktree removal stays strict.\r\n */\r\nexport function skipDependencyCacheRemoval(input: DependencyCacheGuardInput): CleanupSkipReason | null {\r\n const { indexed, nodeModulesAgeMs, ageMs, worktreePath, activeWorktreePaths, diskPressure } =\r\n input;\r\n if (!diskPressure && ageMs < nodeModulesAgeMs) return \"below_age_threshold\";\r\n if (activeWorktreePaths.has(path.resolve(worktreePath))) return \"active_worker\";\r\n if (indexed && isWorkerProcessLive(indexed)) return \"active_worker\";\r\n if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {\r\n return \"dirty_worktree\";\r\n }\r\n return null;\r\n}\r\n\r\n/** Build caches (`.turbo`, `dist`, etc.) use the same relaxed guards as dependency caches. */\r\nexport function skipBuildCacheRemoval(input: DependencyCacheGuardInput): CleanupSkipReason | null {\r\n return skipDependencyCacheRemoval(input);\r\n}\r\n\r\nexport function skipNodeModulesRemoval(input: NodeModulesGuardInput): CleanupSkipReason | null {\r\n return skipDependencyCacheRemoval({\r\n ...input,\r\n worktreePath: input.indexed?.worktreePath ?? \"\",\r\n activeWorktreePaths: new Set(),\r\n diskPressure: false,\r\n });\r\n}\r\n", "import { computeGitAncestry, gitStatusShort } from \"./git.js\";\r\nimport { computeWorkerStatus, type RawHarnessWorkerStatus } from \"./status.js\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupRunLivenessContext } from \"./cleanup-run-liveness.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { prUrlFromFinalResult } from \"./cleanup-worktree-salvage.js\";\r\nimport { isPidAlive } from \"./util.js\";\r\n\r\n/** Lazily compute worker status \u2014 avoids git/stream work for every indexed worker up front. */\r\nexport function indexedWorktreeStatus(entry: IndexedWorktree): RawHarnessWorkerStatus {\r\n if (!entry.status) {\r\n entry.status = computeWorkerStatus(entry.worker, {\r\n base: entry.run.base,\r\n baseCommit: entry.run.baseCommit,\r\n });\r\n }\r\n return entry.status;\r\n}\r\n\r\n/**\r\n * Porcelain-only dirty probe for dependency-cache guards. Skips ancestry/stream\r\n * work that whole-worktree removal needs but `node_modules` GC does not.\r\n */\r\nexport function indexedWorktreeHasMaterialChanges(\r\n entry: IndexedWorktree,\r\n gitStatusCache?: CleanupGitStatusCache,\r\n): boolean {\r\n if (entry.status) {\r\n return materialWorktreeChanges(entry.status.changedFiles).length > 0;\r\n }\r\n const porcelain = gitStatusCache\r\n ? gitStatusCache.porcelain(entry.worktreePath)\r\n : gitStatusShort(entry.worktreePath);\r\n return materialWorktreeChanges(porcelain).length > 0;\r\n}\r\n\r\nfunction finalResultFromWorkerJson(entry: IndexedWorktree): unknown {\r\n const snapshot = entry.worker.completionSnapshot?.finalResult;\r\n if (snapshot !== undefined && snapshot !== null) return snapshot;\r\n if (entry.worker.taskPrUrl) {\r\n return { prUrl: entry.worker.taskPrUrl };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Guard-oriented status: avoids stdout/heartbeat stream parsing for terminal workers\r\n * while preserving salvage semantics (dirty / PR / landing checks).\r\n */\r\nexport function resolveWorktreeGuardStatus(\r\n entry: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): RawHarnessWorkerStatus {\r\n if (entry.status) return entry.status;\r\n\r\n const worker = entry.worker;\r\n const completionAcknowledged =\r\n typeof worker.completionReportedAt === \"string\" && worker.completionReportedAt.trim().length > 0;\r\n const workerJsonTerminal =\r\n Boolean(worker.status && [\"done\", \"exited\", \"blocked\", \"failed\", \"abandoned\"].includes(worker.status)) ||\r\n completionAcknowledged;\r\n const finalResult = finalResultFromWorkerJson(entry);\r\n\r\n if (workerJsonTerminal && !isPidAlive(worker.pid)) {\r\n const changedFiles = ctx?.gitStatusCache\r\n ? ctx.gitStatusCache.porcelain(entry.worktreePath)\r\n : gitStatusShort(entry.worktreePath);\r\n const baseLabel = entry.run.baseCommit?.trim() || entry.run.base?.trim() || \"origin/main\";\r\n const ahead = ctx?.gitRevCache?.countAheadOfMain(entry.worktreePath, baseLabel);\r\n const gitAncestry =\r\n ahead === 0\r\n ? {\r\n checked: true,\r\n base: baseLabel,\r\n relation: \"synced\" as const,\r\n }\r\n : computeGitAncestry(entry.worktreePath, {\r\n base: entry.run.base,\r\n baseCommit: entry.run.baseCommit,\r\n });\r\n const status = {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n pid: worker.pid,\r\n alive: false,\r\n status: worker.status ?? (completionAcknowledged ? \"done\" : \"exited\"),\r\n attention: { state: completionAcknowledged ? \"done\" : \"stale\" },\r\n branch: worker.branch,\r\n worktreePath: entry.worktreePath,\r\n ownedPaths: worker.ownedPaths,\r\n stdoutBytes: 0,\r\n stderrBytes: 0,\r\n heartbeatBytes: 0,\r\n firstEventAt: null,\r\n lastEventAt: null,\r\n lastActivityAt: worker.completionReportedAt ?? null,\r\n currentTool: null,\r\n heartbeatCount: 0,\r\n lastHeartbeatAt: null,\r\n lastHeartbeatPhase: null,\r\n lastHeartbeatSummary: null,\r\n heartbeatBlocker: null,\r\n changedFiles,\r\n gitAncestry,\r\n finalResult,\r\n completionBlocker:\r\n typeof worker.completionBlocker === \"string\" ? worker.completionBlocker.trim() || null : null,\r\n prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? prUrlFromFinalResult(finalResult),\r\n } as unknown as RawHarnessWorkerStatus;\r\n entry.status = status;\r\n return status;\r\n }\r\n\r\n return indexedWorktreeStatus(entry);\r\n}\r\n", "/** Generated install/build trees safe to delete under a harness worktree. */\r\nexport const HARNESS_BUILD_CACHE_RELATIVE_PATHS = [\r\n \".next\",\r\n \".turbo\",\r\n \"dist\",\r\n \"build\",\r\n \".cache\",\r\n \"node_modules/.cache\",\r\n] as const;\r\n\r\nexport type HarnessBuildCacheRelativePath = (typeof HARNESS_BUILD_CACHE_RELATIVE_PATHS)[number];\r\n\r\n/** True when a porcelain path is only generated build/install noise. */\r\nexport function isGeneratedHarnessPath(pathPart: string): boolean {\r\n const normalized = pathPart.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\r\n if (normalized === \"node_modules\" || normalized.startsWith(\"node_modules/\")) return true;\r\n for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {\r\n if (normalized === rel || normalized.startsWith(`${rel}/`)) return true;\r\n }\r\n return false;\r\n}\r\n", "import { isGeneratedHarnessPath } from \"./cleanup-build-cache-paths.js\";\r\n\r\n/** Strip generated install/build trees from porcelain \u2014 they are what cleanup removes. */\r\nexport function materialWorktreeChanges(changedFiles: string[]): string[] {\r\n return changedFiles.filter((line) => {\r\n const trimmed = line.trim();\r\n const pathPart = trimmed.startsWith(\"??\")\r\n ? trimmed.slice(2).trim()\r\n : trimmed.length > 3\r\n ? trimmed.slice(3).trim()\r\n : trimmed;\r\n return !isGeneratedHarnessPath(pathPart);\r\n });\r\n}\r\n", "import type { GitAncestry } from \"./git.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\n\r\nexport function prUrlFromFinalResult(finalResult: unknown): string | null {\r\n if (typeof finalResult === \"string\") {\r\n const match = finalResult.match(/https:\\/\\/github\\.com\\/[^\\s]+\\/pull\\/\\d+/i);\r\n return match?.[0] ?? null;\r\n }\r\n if (finalResult && typeof finalResult === \"object\") {\r\n const obj = finalResult as Record<string, unknown>;\r\n for (const key of [\"prUrl\", \"pr_url\", \"pullRequestUrl\"]) {\r\n const value = obj[key];\r\n if (typeof value === \"string\" && value.trim()) return value.trim();\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/** True when git ancestry shows the worker branch is fully landed on the run base. */\r\nexport function isLandedGitAncestry(ancestry: GitAncestry | null | undefined): boolean {\r\n const relation = ancestry?.relation;\r\n return relation === \"merged\" || relation === \"synced\";\r\n}\r\n\r\n/** Blocks whole-worktree removal when commits are not landed or tree is dirty. */\r\nexport function isPrOrUnmergedWork(status: RawHarnessWorkerStatus): boolean {\r\n const relation = status.gitAncestry?.relation;\r\n if (relation === \"merged\" || relation === \"synced\") {\r\n return materialWorktreeChanges(status.changedFiles).length > 0;\r\n }\r\n if (prUrlFromFinalResult(status.finalResult)) return true;\r\n if (relation === \"ahead\" || relation === \"diverged\") return true;\r\n if (status.changedFiles.length > 0 && status.finalResult) return true;\r\n return false;\r\n}\r\n", "import path from \"node:path\";\r\nimport { listRunRecords, runDirectory, saveRun, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { listRunWorkerNames } from \"./run-worker-index.js\";\r\nimport { computeWorkerStatus, isLandingBlockedWorkerStatus } from \"./status.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\n\r\nexport interface RunFinalizeResult {\r\n runId: string;\r\n from: string;\r\n to: string;\r\n}\r\n\r\n/** Run statuses we treat as \"not yet terminal\" and therefore candidates for finalization. */\r\nexport const ACTIVE_RUN_STATUSES = new Set([\r\n \"running\",\r\n \"dispatching\",\r\n \"pending\",\r\n \"queued\",\r\n \"needs_attention\",\r\n]);\r\n\r\nexport const TERMINAL_RUN_STATUSES = new Set([\"completed\", \"failed\", \"cancelled\", \"done\"]);\r\n\r\n/**\r\n * Decide the terminal status for a run, or null if it should stay active.\r\n * A run is terminal once none of its workers are still alive-and-unfinished.\r\n */\r\nexport function deriveTerminalRunStatus(run: HarnessRunRecord): string | null {\r\n const names = listRunWorkerNames(run);\r\n if (names.length === 0) return \"failed\"; // marked active but never started a worker\r\n let anyAlive = false;\r\n let anyResult = false;\r\n let anyCompletionBlocked = false;\r\n let anyLandingBlocked = false;\r\n for (const name of names) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectory(run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker) continue;\r\n const status = computeWorkerStatus(worker, {\r\n base: run.base,\r\n baseCommit: run.baseCommit,\r\n });\r\n if (status.alive && !status.finalResult) {\r\n anyAlive = true;\r\n break;\r\n }\r\n // A finished worker whose AgentOS completion replay was rejected (e.g. a\r\n // revoked / expired / cross-workspace runner token) is NOT done: its linked\r\n // AgentTask never advanced. Keep the run non-terminal so the pipeline keeps\r\n // retrying completion (and the board surfaces the blocked worker) instead of\r\n // papering an invalid runner token over as `completed`.\r\n if (typeof worker.completionBlocker === \"string\" && worker.completionBlocker) {\r\n anyCompletionBlocked = true;\r\n }\r\n if (isLandingBlockedWorkerStatus(status)) {\r\n anyLandingBlocked = true;\r\n }\r\n if (status.finalResult && status.attention.state === \"done\") anyResult = true;\r\n }\r\n if (anyAlive) return null; // still doing real work \u2014 leave it running\r\n if (anyCompletionBlocked) return null; // completion replay blocked \u2014 not yet terminal\r\n if (anyLandingBlocked) return null; // dirty/unlanded work \u2014 keep run active for operator attention\r\n return anyResult ? \"completed\" : \"failed\";\r\n}\r\n\r\n/**\r\n * Finalize runs that are still marked active but have no live workers.\r\n *\r\n * The harness creates one run per task and never closed them out, leaving dozens\r\n * of \"running\" runs that bloated disk and broke operator views (and made cleanup\r\n * unsafe to reason about). Active-worker accounting already excludes dead workers,\r\n * so this is about run-status hygiene + enabling safe pruning of finished runs.\r\n *\r\n * Returns the runs whose status changed.\r\n */\r\nexport function finalizeStaleRuns(): RunFinalizeResult[] {\r\n const finalized: RunFinalizeResult[] = [];\r\n for (const run of listRunRecords()) {\r\n if (!ACTIVE_RUN_STATUSES.has(run.status)) continue;\r\n const next = deriveTerminalRunStatus(run);\r\n if (!next || next === run.status) continue;\r\n const from = run.status;\r\n run.status = next;\r\n saveRun(run);\r\n finalized.push({ runId: run.id, from, to: next });\r\n }\r\n return finalized;\r\n}\r\n", "import { deriveTerminalRunStatus, TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { indexedWorktreeStatus } from \"./cleanup-index-status.js\";\r\nimport type { CleanupGitRevCache } from \"./cleanup-git-rev-cache.js\";\r\nimport type { CleanupGitStatusCache } from \"./cleanup-git-status-cache.js\";\r\nimport type { CleanupRunTerminalCache } from \"./cleanup-run-terminal-cache.js\";\r\nimport { completionBlockerBlocksWorktreeRemoval } from \"./cleanup-completion-blocker.js\";\r\nimport { isPidAlive } from \"./util.js\";\r\n\r\nconst TERMINAL_WORKER_JSON_STATUSES = new Set([\r\n \"done\",\r\n \"exited\",\r\n \"blocked\",\r\n \"failed\",\r\n \"abandoned\",\r\n]);\r\n\r\nexport interface CleanupRunLivenessContext {\r\n runTerminalCache: CleanupRunTerminalCache;\r\n gitStatusCache: CleanupGitStatusCache;\r\n gitRevCache: CleanupGitRevCache;\r\n}\r\n\r\nfunction deriveRunTerminal(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): string | null {\r\n if (ctx) return ctx.runTerminalCache.derive(indexed.run);\r\n return deriveTerminalRunStatus(indexed.run);\r\n}\r\n\r\n/**\r\n * True when the worker process is still live. Broad cleanup scans use worker.json\r\n * terminal hints before falling back to full `computeWorkerStatus` (expensive).\r\n */\r\nexport function isWorkerProcessLive(indexed: IndexedWorktree): boolean {\r\n if (isPidAlive(indexed.worker.pid)) return true;\r\n if (\r\n typeof indexed.worker.completionReportedAt === \"string\" &&\r\n indexed.worker.completionReportedAt.trim().length > 0\r\n ) {\r\n return false;\r\n }\r\n const workerStatus = indexed.worker.status;\r\n if (workerStatus && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus)) return false;\r\n if (!indexed.worker.pid) {\r\n if (workerStatus !== \"running\") return false;\r\n return indexedWorktreeStatus(indexed).alive;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Run record still marked active but every worker is finished \u2014 safe to treat as\r\n * terminal for GC after `finalizeStaleRuns()` (or when deriveTerminalRunStatus is set).\r\n */\r\nexport function isRunStaleActive(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): boolean {\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;\r\n return deriveRunTerminal(indexed, ctx) !== null;\r\n}\r\n\r\n/**\r\n * Whether the harness run still has unfinished work that should block whole-worktree removal.\r\n * Does not block per-worker `node_modules` when only this worker is finished.\r\n */\r\nexport function runBlocksWorktreeRemoval(\r\n indexed: IndexedWorktree,\r\n ctx?: CleanupRunLivenessContext,\r\n): boolean {\r\n if (isWorkerProcessLive(indexed)) return true;\r\n const workerStatus = indexed.worker.status;\r\n if (\r\n workerStatus &&\r\n TERMINAL_WORKER_JSON_STATUSES.has(workerStatus) &&\r\n !indexed.worker.completionBlocker\r\n ) {\r\n return false;\r\n }\r\n const status = indexedWorktreeStatus(indexed);\r\n if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;\r\n // Finished dead workers are not held back by run-level bookkeeping (siblings, stale run.json).\r\n if (isFinishedWorkerStatus(status)) return false;\r\n if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;\r\n if (isRunStaleActive(indexed, ctx)) return false;\r\n return deriveRunTerminal(indexed, ctx) === null;\r\n}\r\n", "import { assessWorkerLanding } from \"./landing-gate.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\nimport { indexedWorktreeStatus } from \"./cleanup-index-status.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport { isWorkerProcessLive } from \"./cleanup-run-liveness.js\";\r\nimport type { RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { isFinishedWorkerStatus } from \"./status.js\";\r\nimport { isPrOrUnmergedWork, prUrlFromFinalResult } from \"./cleanup-worktree-salvage.js\";\r\n\r\n/**\r\n * Whether a persisted `completionBlocker` should still block whole-worktree removal.\r\n *\r\n * Dead workers with landed/clean work may keep replay metadata on disk after the\r\n * board advanced externally \u2014 those blockers are stale for GC and must not pin\r\n * worktrees indefinitely.\r\n */\r\nexport function completionBlockerBlocksWorktreeRemoval(\r\n indexed: IndexedWorktree,\r\n status?: RawHarnessWorkerStatus,\r\n): boolean {\r\n const blocker =\r\n typeof indexed.worker.completionBlocker === \"string\" ? indexed.worker.completionBlocker.trim() : \"\";\r\n if (!blocker) return false;\r\n if (isWorkerProcessLive(indexed)) return true;\r\n\r\n const resolved = status ?? indexedWorktreeStatus(indexed);\r\n if (!isFinishedWorkerStatus(resolved)) return true;\r\n if (isPrOrUnmergedWork(resolved)) return true;\r\n if (materialWorktreeChanges(resolved.changedFiles).length > 0) return true;\r\n\r\n const landing = assessWorkerLanding({\r\n finalResult: resolved.finalResult,\r\n changedFiles: resolved.changedFiles,\r\n gitAncestry: resolved.gitAncestry,\r\n prUrl: prUrlFromFinalResult(resolved.finalResult),\r\n });\r\n if (landing.blocked) return true;\r\n\r\n return false;\r\n}\r\n", "export type CleanupActionKind =\r\n | \"remove_node_modules\"\r\n | \"remove_next_cache\"\r\n | \"remove_build_cache\"\r\n | \"remove_worktree\"\r\n | \"remove_run_directory\";\r\n\r\nexport type CleanupSkipReason =\r\n | \"dry_run\"\r\n | \"below_age_threshold\"\r\n | \"active_worker\"\r\n | \"dirty_worktree\"\r\n | \"landing_blocked\"\r\n | \"pr_or_unmerged_commits\"\r\n | \"completion_blocked\"\r\n | \"run_still_active\"\r\n | \"path_outside_harness\"\r\n | \"worktrees_disabled\"\r\n | \"orphan_without_flag\"\r\n | \"missing_worktree\"\r\n | \"remove_failed\"\r\n /** Generated cache owned by another user (often root); daemon cannot unlink without privileged reclaim. */\r\n | \"foreign_owner\"\r\n /** Harness `runs/` metadata must never be removed by worktree GC. */\r\n | \"run_metadata_protected\"\r\n /** AgentOS / operator lifecycle overlay blocked removal (see `detail`). */\r\n | \"board_lifecycle_blocked\";\r\n\r\nexport interface CleanupCandidate {\r\n kind: CleanupActionKind;\r\n path: string;\r\n bytes: number | null;\r\n harnessRoot?: string;\r\n runId?: string;\r\n worker?: string;\r\n repo?: string;\r\n ageMs: number;\r\n}\r\n\r\nexport interface CleanupAction extends CleanupCandidate {\r\n executed: boolean;\r\n skipped: boolean;\r\n skipReason?: CleanupSkipReason;\r\n error?: string;\r\n}\r\n\r\nexport interface RunFinalizeSummary {\r\n runId: string;\r\n from: string;\r\n to: string;\r\n}\r\n\r\nexport interface HarnessStorageSnapshotShape {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n worktreesBytes: number | null;\r\n runCount: number;\r\n workerCount: number;\r\n oldestRunAt: string | null;\r\n scannedAt: string;\r\n}\r\n\r\nexport interface HarnessCleanupSummary {\r\n harnessRoot: string;\r\n /** Every harness tree scanned (primary + well-known extras). */\r\n scanRoots: string[];\r\n dryRun: boolean;\r\n execute: boolean;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n includeOrphans: boolean;\r\n diskPressure?: boolean;\r\n diskGate?: {\r\n ok: boolean;\r\n path: string;\r\n freeBytes: number;\r\n usedPercent: number;\r\n reason: string | null;\r\n };\r\n scannedAt: string;\r\n finalizedRuns: RunFinalizeSummary[];\r\n actions: CleanupAction[];\r\n skips: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>;\r\n totals: {\r\n candidateBytes: number;\r\n reclaimableBytes: number;\r\n removedBytes: number;\r\n removedPaths: number;\r\n skippedPaths: number;\r\n skipReasons: Partial<Record<CleanupSkipReason, number>>;\r\n };\r\n /** Disk-pressure evidence \u2014 present when bytes accounting is enabled. */\r\n storage?: HarnessStorageSnapshotShape;\r\n /** Sample of paths kept because workers/runs are still live (for operator summaries). */\r\n preservedLivePaths?: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>;\r\n /** Empty harness worktree run directories removed after worker worktrees were reclaimed. */\r\n removedRunDirectories?: number;\r\n /** Bounded operator rollup (always attached; use `kynver cleanup --compact` to emit alone). */\r\n compactSummary?: import(\"./cleanup-summary.js\").CleanupCompactSummary;\r\n}\r\n\r\nexport interface WorktreeRemovalGuardInput {\r\n worktreePath: string;\r\n /** True when `buildWorktreeIndex()` has a worker.json entry for this path. */\r\n indexed: boolean;\r\n runId?: string;\r\n worker?: string;\r\n}\r\n\r\n/** Optional overlay (e.g. AgentOS board + lease checks) evaluated after runtime salvage gates. */\r\nexport type WorktreeRemovalGuardHook = (\r\n input: WorktreeRemovalGuardInput,\r\n) => { reason: CleanupSkipReason; detail?: string } | null;\r\n\r\nexport interface HarnessCleanupOptions {\r\n harnessRoot?: string;\r\n /** When false (default), only report candidates. */\r\n execute?: boolean;\r\n /** When true (default), call `finalizeStaleRuns()` before scanning. */\r\n finalizeStaleRuns?: boolean;\r\n /** When true, estimate candidate bytes for guard-passing removals only. CLI defaults false. */\r\n accountBytes?: boolean;\r\n /** Per-run entry cap for storage snapshot byte totals (`0` = counts only). */\r\n storagePerRunEntryCap?: number | null;\r\n /** Per-candidate filesystem walk cap when `du` is unavailable. */\r\n byteAccountingEntryCap?: number;\r\n /** Minimum age before removing generated `node_modules` (default 6h). */\r\n nodeModulesAgeMs?: number;\r\n /** When 0 or unset, worktree removal is disabled. */\r\n worktreesAgeMs?: number;\r\n /**\r\n * Age threshold for worktrees whose harness run is already terminal\r\n * (`completed` / `failed` / `cancelled` / `done`). Salvage gates still apply.\r\n */\r\n terminalWorktreesAgeMs?: number;\r\n /** Minimum age before removing an empty `worktrees/<runId>/` directory. */\r\n runDirectoriesAgeMs?: number;\r\n /** Cap actions evaluated per sweep (cron/watchdog boundedness). */\r\n maxActionsPerSweep?: number;\r\n /** Allow cleaning `node_modules` under worktrees with no worker index entry. */\r\n includeOrphans?: boolean;\r\n /** When set, only consider workers for this harness run (pipeline tick scope). */\r\n runIdFilter?: string;\r\n now?: number;\r\n /** When set, invoked for each worktree candidate after built-in salvage guards. */\r\n worktreeRemovalGuard?: WorktreeRemovalGuardHook;\r\n}\r\n\r\n/** Conservative default aligned with 2026-05-27 manual harness cleanup (6h). */\r\nexport const DEFAULT_NODE_MODULES_AGE_MS = 6 * 60 * 60 * 1000;\r\n\r\n/** Seven days \u2014 only used when worktree cleanup is explicitly enabled. */\r\nexport const DEFAULT_WORKTREES_AGE_MS = 7 * 24 * 60 * 60 * 1000;\r\n\r\n/** Terminal runs: salvage-first worktree removal after workers finish (6h default). */\r\nexport const DEFAULT_TERMINAL_WORKTREES_AGE_MS = DEFAULT_NODE_MODULES_AGE_MS;\r\n\r\n/** Empty per-run worktree folders under `worktrees/<runId>/`. */\r\nexport const DEFAULT_RUN_DIRECTORIES_AGE_MS = 60 * 60 * 1000;\r\n\r\n/** Bounded cron/watchdog scan \u2014 skip remaining candidates when exceeded. */\r\nexport const DEFAULT_MAX_ACTIONS_PER_SWEEP = 120;\r\n\r\nexport const MAX_PRESERVED_LIVE_PATH_SAMPLES = 24;\r\n", "import type { CleanupAction, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport { MAX_PRESERVED_LIVE_PATH_SAMPLES } from \"./cleanup-types.js\";\r\n\r\nconst LIVE_SKIP_REASONS = new Set<CleanupSkipReason>([\r\n \"active_worker\",\r\n \"run_still_active\",\r\n \"completion_blocked\",\r\n \"landing_blocked\",\r\n]);\r\n\r\nexport function collectPreservedLivePaths(\r\n actions: CleanupAction[],\r\n skips: Array<{ path: string; reason: CleanupSkipReason; detail?: string }>,\r\n): Array<{ path: string; reason: CleanupSkipReason; detail?: string }> {\r\n const out: Array<{ path: string; reason: CleanupSkipReason; detail?: string }> = [];\r\n const seen = new Set<string>();\r\n\r\n const push = (path: string, reason: CleanupSkipReason, detail?: string) => {\r\n const key = `${path}\\0${reason}`;\r\n if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;\r\n seen.add(key);\r\n out.push({ path, reason, ...(detail ? { detail } : {}) });\r\n };\r\n\r\n for (const skip of skips) {\r\n if (!LIVE_SKIP_REASONS.has(skip.reason)) continue;\r\n push(skip.path, skip.reason, skip.detail);\r\n }\r\n for (const action of actions) {\r\n if (!action.skipped || !action.skipReason) continue;\r\n if (!LIVE_SKIP_REASONS.has(action.skipReason)) continue;\r\n push(action.path, action.skipReason);\r\n }\r\n\r\n return out;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport type { ActiveWorktreeGuardSnapshot } from \"./cleanup-active-worktrees.js\";\r\nimport { isWorktreeOnLiveRun } from \"./cleanup-active-worktrees.js\";\r\nimport { deriveTerminalRunStatus, TERMINAL_RUN_STATUSES } from \"./finalize.js\";\r\nimport { readJson } from \"./util.js\";\r\nimport type { HarnessRunRecord } from \"./run-store.js\";\r\n\r\nexport interface ScanRunDirectoryOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n runDirectoriesAgeMs: number;\r\n runIdFilter?: string;\r\n activeGuards: ActiveWorktreeGuardSnapshot;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction loadRunStatus(harnessRoot: string, runId: string): HarnessRunRecord | null {\r\n const runPath = path.join(harnessRoot, \"runs\", runId, \"run.json\");\r\n if (!existsSync(runPath)) return null;\r\n return readJson<HarnessRunRecord | null>(runPath, null);\r\n}\r\n\r\nfunction runDirectoryIsEmpty(runPath: string): boolean {\r\n try {\r\n const entries = readdirSync(runPath);\r\n return entries.length === 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function skipRunDirectoryRemoval(input: {\r\n harnessRoot: string;\r\n runId: string;\r\n runPath: string;\r\n ageMs: number;\r\n runDirectoriesAgeMs: number;\r\n activeGuards: ActiveWorktreeGuardSnapshot;\r\n}): CleanupSkipReason | null {\r\n const { harnessRoot, runId, runPath, ageMs, runDirectoriesAgeMs, activeGuards } = input;\r\n if (isWorktreeOnLiveRun(runPath, harnessRoot, runId, activeGuards.liveRunKeys)) {\r\n return \"run_still_active\";\r\n }\r\n if (!runDirectoryIsEmpty(runPath)) return \"run_still_active\";\r\n const run = loadRunStatus(harnessRoot, runId);\r\n if (run && !TERMINAL_RUN_STATUSES.has(run.status)) {\r\n if (!deriveTerminalRunStatus(run)) return \"run_still_active\";\r\n }\r\n if (runDirectoriesAgeMs > 0 && ageMs < runDirectoriesAgeMs) return \"below_age_threshold\";\r\n return null;\r\n}\r\n\r\n/** Empty per-run folders under `worktrees/<runId>/` after worker worktrees are gone. */\r\nexport function scanStaleRunDirectoryCandidates(\r\n opts: ScanRunDirectoryOptions,\r\n): CleanupCandidate[] {\r\n if (!existsSync(opts.worktreesDir)) return [];\r\n const candidates: CleanupCandidate[] = [];\r\n let entries;\r\n try {\r\n entries = readdirSync(opts.worktreesDir, { withFileTypes: true });\r\n } catch {\r\n return [];\r\n }\r\n\r\n for (const runEntry of entries) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runId = runEntry.name;\r\n if (opts.runIdFilter && runId !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runId);\r\n if (!runDirectoryIsEmpty(runPath)) continue;\r\n candidates.push({\r\n kind: \"remove_run_directory\",\r\n path: runPath,\r\n bytes: null,\r\n harnessRoot: opts.harnessRoot,\r\n runId,\r\n ageMs: pathAgeMs(runPath, opts.now),\r\n });\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { listRunRecordsForHarnessRoot, runDirectoryAt } from \"./run-store.js\";\r\nimport { harnessRunsDir, harnessWorktreesDir } from \"./paths.js\";\r\nimport {\r\n collectFilesystemLiveRunKeys,\r\n RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n} from \"./run-metadata-retention.js\";\r\nimport type { HarnessWorkerRecord } from \"./status.js\";\r\nimport { readJson, safeSlug, isPidAlive } from \"./util.js\";\r\n\r\nexport interface ActiveWorktreeGuardSnapshot {\r\n /** Resolved worktree paths that must keep dependency caches. */\r\n activeWorktreePaths: Set<string>;\r\n /** `${harnessRoot}\\0${runId}` keys for runs with at least one live worker. */\r\n liveRunKeys: Set<string>;\r\n}\r\n\r\nfunction workerHasRecentHarnessActivity(worker: HarnessWorkerRecord, now: number): boolean {\r\n const paths = [worker.heartbeatPath, worker.stdoutPath, worker.stderrPath];\r\n for (const target of paths) {\r\n if (!existsSync(target)) continue;\r\n try {\r\n const age = now - statSync(target).mtimeMs;\r\n if (Number.isFinite(age) && age >= 0 && age < RUN_METADATA_ACTIVE_SIGNAL_MS) return true;\r\n } catch {\r\n // ignore unreadable artifact\r\n }\r\n }\r\n return false;\r\n}\r\n\r\n/** Fast liveness probe \u2014 avoids full `computeWorkerStatus` during broad cleanup scans. */\r\nfunction isActiveHarnessWorker(worker: HarnessWorkerRecord, now: number): boolean {\r\n if (isPidAlive(worker.pid)) return true;\r\n if (worker.status === \"running\" && workerHasRecentHarnessActivity(worker, now)) return true;\r\n return false;\r\n}\r\n\r\n/** Collect worktrees/runs that still have live worker processes (current-run guard). */\r\nexport function collectActiveWorktreeGuards(\r\n harnessRoots: string[],\r\n now = Date.now(),\r\n): ActiveWorktreeGuardSnapshot {\r\n const activeWorktreePaths = new Set<string>();\r\n const liveRunKeys = new Set<string>();\r\n\r\n for (const harnessRoot of harnessRoots) {\r\n for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {\r\n let runHasLive = false;\r\n for (const name of Object.keys(run.workers || {})) {\r\n const worker = readJson<HarnessWorkerRecord | undefined>(\r\n path.join(runDirectoryAt(harnessRoot, run.id), \"workers\", safeSlug(name), \"worker.json\"),\r\n undefined,\r\n );\r\n if (!worker?.worktreePath) continue;\r\n const worktreePath = path.resolve(worker.worktreePath);\r\n if (!isActiveHarnessWorker(worker, now)) continue;\r\n runHasLive = true;\r\n activeWorktreePaths.add(worktreePath);\r\n }\r\n if (runHasLive) liveRunKeys.add(`${harnessRoot}\\0${run.id}`);\r\n }\r\n for (const key of collectFilesystemLiveRunKeys(harnessRoot)) {\r\n liveRunKeys.add(key);\r\n }\r\n }\r\n\r\n return { activeWorktreePaths, liveRunKeys };\r\n}\r\n\r\n/** True when a worktree path still exists under a live run (belt-and-suspenders). */\r\nexport function isWorktreeOnLiveRun(\r\n worktreePath: string,\r\n harnessRoot: string,\r\n runId: string | undefined,\r\n liveRunKeys: Set<string>,\r\n): boolean {\r\n if (!runId) return false;\r\n return liveRunKeys.has(`${harnessRoot}\\0${runId}`);\r\n}\r\n\r\nexport function worktreesDirForRoot(harnessRoot: string): string {\r\n return harnessWorktreesDir(harnessRoot);\r\n}\r\n\r\nexport function runsDirForRoot(harnessRoot: string): string {\r\n return harnessRunsDir(harnessRoot);\r\n}\r\n\r\nexport function harnessRootExists(harnessRoot: string): boolean {\r\n return existsSync(harnessRoot);\r\n}\r\n\r\nexport function listWorktreeRunIds(worktreesDir: string): string[] {\r\n if (!existsSync(worktreesDir)) return [];\r\n try {\r\n return readdirSync(worktreesDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { resolveDefaultRepo } from \"./default-repo.js\";\r\nimport { parseHeartbeat } from \"./heartbeat.js\";\r\nimport { harnessRunsDir, normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport { saveRun, type HarnessRunRecord } from \"./run-store.js\";\r\nimport { canonicalWorkerDir, workerArtifactPaths } from \"./worker-metadata-paths.js\";\r\nimport { isPidAlive, readJson, safeSlug } from \"./util.js\";\r\n\r\n/** Recent heartbeat/stdout activity \u2014 treat run metadata as live. */\r\nexport const RUN_METADATA_ACTIVE_SIGNAL_MS = 15 * 60 * 1000;\r\n\r\nexport interface RunMetadataRetentionOutcome {\r\n runId: string;\r\n action: \"repaired_run_json\" | \"skipped\";\r\n reason: string;\r\n}\r\n\r\nexport interface RunMetadataRetentionResult {\r\n runs: RunMetadataRetentionOutcome[];\r\n}\r\n\r\n/** True when `targetPath` lives under `{harnessRoot}/runs/` (run + worker metadata). */\r\nexport function isHarnessRunMetadataPath(targetPath: string, harnessRoot: string): boolean {\r\n const resolved = path.resolve(targetPath);\r\n const runsDir = path.resolve(harnessRunsDir(harnessRoot));\r\n const rel = path.relative(runsDir, resolved);\r\n return rel !== \"..\" && !rel.startsWith(\"..\") && !path.isAbsolute(rel);\r\n}\r\n\r\nfunction listRunDirIds(runsDir: string): string[] {\r\n if (!existsSync(runsDir)) return [];\r\n try {\r\n return readdirSync(runsDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory() && entry.name !== \"runs\")\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction listWorkerNamesOnDisk(runDir: string): string[] {\r\n const workersDir = path.join(runDir, \"workers\");\r\n if (!existsSync(workersDir)) return [];\r\n try {\r\n return readdirSync(workersDir, { withFileTypes: true })\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => entry.name);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction pathRecentlyTouched(target: string, now: number, windowMs: number): boolean {\r\n if (!existsSync(target)) return false;\r\n try {\r\n const age = now - statSync(target).mtimeMs;\r\n return Number.isFinite(age) && age >= 0 && age < windowMs;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/** Worker dir still has live process or recent harness artifacts \u2014 retain metadata. */\r\nexport function workerDirHasActiveRetentionSignals(\r\n workerDir: string,\r\n now = Date.now(),\r\n windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n): boolean {\r\n if (!existsSync(workerDir)) return false;\r\n const artifacts = workerArtifactPaths(workerDir);\r\n const worker = readJson<{ status?: string; pid?: number } | undefined>(\r\n artifacts.workerJsonPath,\r\n undefined,\r\n );\r\n if (worker?.status === \"running\" && isPidAlive(worker.pid)) return true;\r\n const heartbeat = parseHeartbeat(artifacts.heartbeatPath);\r\n if (heartbeat.lastHeartbeatAt) {\r\n const age = now - Date.parse(heartbeat.lastHeartbeatAt);\r\n if (Number.isFinite(age) && age >= 0 && age < windowMs) return true;\r\n }\r\n if (pathRecentlyTouched(artifacts.stdoutPath, now, windowMs)) return true;\r\n if (pathRecentlyTouched(artifacts.heartbeatPath, now, windowMs)) return true;\r\n return false;\r\n}\r\n\r\n/** Any worker under a run dir still looks active \u2014 block metadata deletion/relocation. */\r\nexport function runDirHasActiveRetentionSignals(\r\n runDir: string,\r\n now = Date.now(),\r\n windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS,\r\n): boolean {\r\n for (const name of listWorkerNamesOnDisk(runDir)) {\r\n if (workerDirHasActiveRetentionSignals(path.join(runDir, \"workers\", name), now, windowMs)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nfunction inferRepoFields(): Pick<HarnessRunRecord, \"repo\" | \"base\" | \"baseCommit\"> {\r\n const resolved = resolveDefaultRepo();\r\n return {\r\n repo: resolved?.repo ?? \"\",\r\n base: \"origin/main\",\r\n baseCommit: \"unknown\",\r\n };\r\n}\r\n\r\nfunction synthesizeRunFromDisk(harnessRoot: string, runId: string): HarnessRunRecord | null {\r\n const runDir = path.join(harnessRunsDir(harnessRoot), safeSlug(runId));\r\n if (!existsSync(runDir)) return null;\r\n const workerNames = listWorkerNamesOnDisk(runDir);\r\n if (workerNames.length === 0) return null;\r\n\r\n let createdAt: string;\r\n try {\r\n createdAt = statSync(runDir).birthtime.toISOString();\r\n } catch {\r\n createdAt = new Date().toISOString();\r\n }\r\n\r\n const workers: HarnessRunRecord[\"workers\"] = {};\r\n for (const name of workerNames) {\r\n const canonicalDir = canonicalWorkerDir(harnessRoot, runId, name);\r\n workers[name] = {\r\n workerDir: canonicalDir,\r\n statusPath: path.join(canonicalDir, \"worker.json\"),\r\n };\r\n }\r\n\r\n const hasActive = runDirHasActiveRetentionSignals(runDir);\r\n return {\r\n id: runId,\r\n name: runId,\r\n ...inferRepoFields(),\r\n status: hasActive ? \"running\" : \"needs_attention\",\r\n createdAt,\r\n workers,\r\n };\r\n}\r\n\r\n/**\r\n * Rebuild missing `run.json` files from on-disk worker dirs so reconcile/status\r\n * cannot go blind while worker processes or fresh artifacts remain.\r\n */\r\nexport function repairMissingRunMetadata(harnessRootInput?: string): RunMetadataRetentionResult {\r\n const harnessRoot = normalizeHarnessRoot(harnessRootInput ?? resolveHarnessRoot());\r\n const runsDir = harnessRunsDir(harnessRoot);\r\n const outcomes: RunMetadataRetentionOutcome[] = [];\r\n\r\n for (const runId of listRunDirIds(runsDir)) {\r\n const runJsonPath = path.join(runsDir, runId, \"run.json\");\r\n if (existsSync(runJsonPath)) {\r\n outcomes.push({\r\n runId,\r\n action: \"skipped\",\r\n reason: \"run.json present\",\r\n });\r\n continue;\r\n }\r\n\r\n const synthesized = synthesizeRunFromDisk(harnessRoot, runId);\r\n if (!synthesized) {\r\n outcomes.push({\r\n runId,\r\n action: \"skipped\",\r\n reason: \"no worker dirs on disk\",\r\n });\r\n continue;\r\n }\r\n\r\n saveRun(synthesized);\r\n outcomes.push({\r\n runId,\r\n action: \"repaired_run_json\",\r\n reason: runDirHasActiveRetentionSignals(path.join(runsDir, runId))\r\n ? \"synthesized run.json while worker artifacts still active\"\r\n : \"synthesized run.json from orphan worker metadata dirs\",\r\n });\r\n }\r\n\r\n return { runs: outcomes };\r\n}\r\n\r\n/** `${harnessRoot}\\0${runId}` keys for runs with filesystem active-retention signals. */\r\nexport function collectFilesystemLiveRunKeys(harnessRoot: string, now = Date.now()): Set<string> {\r\n const keys = new Set<string>();\r\n const runsDir = harnessRunsDir(harnessRoot);\r\n for (const runId of listRunDirIds(runsDir)) {\r\n const runDir = path.join(runsDir, runId);\r\n if (runDirHasActiveRetentionSignals(runDir, now)) {\r\n keys.add(`${harnessRoot}\\0${runId}`);\r\n }\r\n }\r\n return keys;\r\n}\r\n", "import path from \"node:path\";\r\nimport { loadUserConfig, saveUserConfig, type KynverUserConfig } from \"./config.js\";\r\nimport {\r\n discoverDefaultRepo,\r\n type DefaultRepoDiscoverySource,\r\n type DiscoveredDefaultRepo,\r\n} from \"./default-repo-discovery.js\";\r\nimport { displayUserPath, redactHomePath, resolveUserPath } from \"./path-values.js\";\r\n\r\nexport type DefaultRepoSource =\r\n | \"config\"\r\n | \"env_default_repo\"\r\n | \"env_harness_repo\"\r\n | DefaultRepoDiscoverySource;\r\n\r\nexport interface ResolvedDefaultRepo {\r\n repo: string;\r\n source: DefaultRepoSource;\r\n persistedInConfig: boolean;\r\n}\r\n\r\nexport interface ResolveDefaultRepoOptions {\r\n config?: KynverUserConfig;\r\n env?: NodeJS.ProcessEnv;\r\n cwd?: string;\r\n runtimeModuleUrl?: string;\r\n}\r\n\r\nfunction expandConfiguredRepo(value: string): string {\r\n return path.resolve(resolveUserPath(value.trim()));\r\n}\r\n\r\nfunction fromConfigured(\r\n value: string | undefined,\r\n source: Extract<DefaultRepoSource, \"config\" | \"env_default_repo\" | \"env_harness_repo\">,\r\n persistedInConfig: boolean,\r\n): ResolvedDefaultRepo | null {\r\n const trimmed = value?.trim();\r\n if (!trimmed) return null;\r\n return {\r\n repo: expandConfiguredRepo(trimmed),\r\n source,\r\n persistedInConfig,\r\n };\r\n}\r\n\r\nexport function resolveDefaultRepo(opts: ResolveDefaultRepoOptions = {}): ResolvedDefaultRepo | null {\r\n const env = opts.env ?? process.env;\r\n const config = opts.config ?? loadUserConfig();\r\n\r\n const fromConfig = fromConfigured(config.defaultRepo, \"config\", true);\r\n if (fromConfig) return fromConfig;\r\n\r\n const fromDefaultEnv = fromConfigured(env.KYNVER_DEFAULT_REPO, \"env_default_repo\", false);\r\n if (fromDefaultEnv) return fromDefaultEnv;\r\n\r\n const fromHarnessEnv = fromConfigured(env.KYNVER_HARNESS_REPO, \"env_harness_repo\", false);\r\n if (fromHarnessEnv) return fromHarnessEnv;\r\n\r\n const discovered = discoverDefaultRepo({\r\n cwd: opts.cwd,\r\n runtimeModuleUrl: opts.runtimeModuleUrl,\r\n });\r\n if (!discovered) return null;\r\n\r\n return {\r\n repo: discovered.repo,\r\n source: discovered.source,\r\n persistedInConfig: false,\r\n };\r\n}\r\n\r\nexport function persistDefaultRepo(repo: string, existing?: KynverUserConfig): KynverUserConfig {\r\n const config: KynverUserConfig = {\r\n ...(existing ?? loadUserConfig()),\r\n defaultRepo: redactHomePath(path.resolve(repo)),\r\n };\r\n saveUserConfig(config);\r\n return config;\r\n}\r\n\r\nexport function remediateDefaultRepo(opts?: ResolveDefaultRepoOptions): {\r\n ok: true;\r\n resolved: ResolvedDefaultRepo;\r\n config: KynverUserConfig;\r\n} | {\r\n ok: false;\r\n reason: string;\r\n} {\r\n const existing = opts?.config ?? loadUserConfig();\r\n const resolved = resolveDefaultRepo({ ...opts, config: existing });\r\n if (!resolved) {\r\n return {\r\n ok: false,\r\n reason:\r\n \"No Kynver git checkout found. Clone the repo, cd into it, then run `kynver setup --repo /path/to/Kynver` (or export KYNVER_DEFAULT_REPO).\",\r\n };\r\n }\r\n\r\n if (resolved.persistedInConfig) {\r\n return { ok: true, resolved, config: existing };\r\n }\r\n\r\n const config = persistDefaultRepo(resolved.repo, existing);\r\n return {\r\n ok: true,\r\n resolved: { ...resolved, persistedInConfig: true, source: \"config\" },\r\n config,\r\n };\r\n}\r\n\r\nexport function formatResolvedDefaultRepo(resolved: ResolvedDefaultRepo): {\r\n defaultRepo: string;\r\n source: DefaultRepoSource;\r\n persistedInConfig: boolean;\r\n} {\r\n return {\r\n defaultRepo: displayUserPath(resolved.repo),\r\n source: resolved.source,\r\n persistedInConfig: resolved.persistedInConfig,\r\n };\r\n}\r\n\r\nexport type { DiscoveredDefaultRepo };\r\n", "import path from \"node:path\";\r\nimport { harnessRunsDir, normalizeHarnessRoot } from \"./paths.js\";\r\nimport { safeSlug } from \"./util.js\";\r\n\r\nconst NESTED_RUNS = `${path.sep}runs${path.sep}runs${path.sep}`;\r\n\r\n/** True when a persisted harness path contains the historical `runs/runs` segment. */\r\nexport function hasNestedRunsSegment(filePath: string): boolean {\r\n return filePath.includes(NESTED_RUNS);\r\n}\r\n\r\n/**\r\n * Rewrite a nested `.../runs/runs/<runId>/...` path to canonical `.../runs/<runId>/...`.\r\n * Returns the input unchanged when no nested segment is present.\r\n */\r\nexport function repairNestedRunsPath(filePath: string, harnessRoot: string): string {\r\n if (!hasNestedRunsSegment(filePath)) return filePath;\r\n const root = normalizeHarnessRoot(harnessRoot);\r\n const runsDir = harnessRunsDir(root);\r\n const marker = `${path.sep}runs${path.sep}runs${path.sep}`;\r\n const idx = filePath.indexOf(marker);\r\n if (idx < 0) return filePath;\r\n const tail = filePath.slice(idx + marker.length);\r\n return path.join(runsDir, tail);\r\n}\r\n\r\nexport function canonicalRunDir(harnessRoot: string, runId: string): string {\r\n return path.join(harnessRunsDir(normalizeHarnessRoot(harnessRoot)), safeSlug(runId));\r\n}\r\n\r\nexport function canonicalWorkerDir(harnessRoot: string, runId: string, workerName: string): string {\r\n return path.join(canonicalRunDir(harnessRoot, runId), \"workers\", safeSlug(workerName));\r\n}\r\n\r\n/** Historical mistaken layout when harness root ended in `/runs`. */\r\nexport function legacyNestedWorkerDir(harnessRoot: string, runId: string, workerName: string): string {\r\n const root = normalizeHarnessRoot(harnessRoot);\r\n return path.join(root, \"runs\", \"runs\", safeSlug(runId), \"workers\", safeSlug(workerName));\r\n}\r\n\r\nexport function workerArtifactFileNames(): readonly string[] {\r\n return [\r\n \"stdout.jsonl\",\r\n \"stderr.log\",\r\n \"heartbeat.jsonl\",\r\n \"last-status.json\",\r\n \"auto-complete.log\",\r\n \"worker.json\",\r\n ] as const;\r\n}\r\n\r\nexport function workerArtifactPaths(workerDir: string): {\r\n workerJsonPath: string;\r\n stdoutPath: string;\r\n stderrPath: string;\r\n heartbeatPath: string;\r\n lastStatusPath: string;\r\n} {\r\n return {\r\n workerJsonPath: path.join(workerDir, \"worker.json\"),\r\n stdoutPath: path.join(workerDir, \"stdout.jsonl\"),\r\n stderrPath: path.join(workerDir, \"stderr.log\"),\r\n heartbeatPath: path.join(workerDir, \"heartbeat.jsonl\"),\r\n lastStatusPath: path.join(workerDir, \"last-status.json\"),\r\n };\r\n}\r\n\r\n/** Resolve the best on-disk worker.json path for a run worker entry. */\r\nexport function resolveWorkerJsonPath(input: {\r\n harnessRoot: string;\r\n runId: string;\r\n workerName: string;\r\n statusPath?: string;\r\n}): string {\r\n const canonical = workerArtifactPaths(canonicalWorkerDir(input.harnessRoot, input.runId, input.workerName))\r\n .workerJsonPath;\r\n if (input.statusPath && !hasNestedRunsSegment(input.statusPath)) {\r\n return input.statusPath;\r\n }\r\n return canonical;\r\n}\r\n", "import { existsSync, rmSync } from \"node:fs\";\r\nimport { git } from \"./git.js\";\r\nimport type { CleanupAction, CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport {\r\n isHarnessBuildCachePath,\r\n isHarnessNextCachePath,\r\n isHarnessNodeModulesPath,\r\n} from \"./cleanup-harness-path-validate.js\";\r\nimport { removeHarnessGeneratedPath } from \"./cleanup-remove-path.js\";\r\nimport { isHarnessRunMetadataPath } from \"./run-metadata-retention.js\";\r\n\r\nexport { isHarnessBuildCachePath, isHarnessNextCachePath, isHarnessNodeModulesPath } from \"./cleanup-harness-path-validate.js\";\r\n\r\nfunction skipRunMetadataRemoval(candidate: CleanupCandidate): CleanupAction | null {\r\n const harnessRoot = candidate.harnessRoot;\r\n if (!harnessRoot || !isHarnessRunMetadataPath(candidate.path, harnessRoot)) return null;\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"run_metadata_protected\",\r\n };\r\n}\r\n\r\nfunction removeDependencyCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n const outcome = removeHarnessGeneratedPath(candidate, execute);\r\n return {\r\n ...candidate,\r\n bytes: outcome.bytes ?? candidate.bytes,\r\n executed: outcome.executed,\r\n skipped: outcome.skipped,\r\n skipReason: outcome.skipReason,\r\n error: outcome.error,\r\n };\r\n}\r\n\r\nexport function removeNodeModules(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeNextCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeBuildCache(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n return removeDependencyCache(candidate, execute);\r\n}\r\n\r\nexport function removeRunDirectory(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n if (!existsSync(candidate.path)) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"missing_worktree\",\r\n };\r\n }\r\n if (!execute) {\r\n return { ...candidate, executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n try {\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n rmSync(candidate.path, { recursive: true, force: true });\r\n return {\r\n ...candidate,\r\n bytes: bytesBefore,\r\n executed: true,\r\n skipped: false,\r\n };\r\n } catch (error) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\nexport function removeWorktree(candidate: CleanupCandidate, execute: boolean): CleanupAction {\r\n const metadataSkip = skipRunMetadataRemoval(candidate);\r\n if (metadataSkip) return metadataSkip;\r\n if (!existsSync(candidate.path)) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"missing_worktree\",\r\n };\r\n }\r\n if (!execute) {\r\n return { ...candidate, executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n const repo = candidate.repo;\r\n try {\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n if (repo) {\r\n git(repo, [\"worktree\", \"remove\", \"--force\", candidate.path], { allowFailure: true });\r\n }\r\n if (existsSync(candidate.path)) {\r\n rmSync(candidate.path, { recursive: true, force: true });\r\n }\r\n return {\r\n ...candidate,\r\n bytes: bytesBefore,\r\n executed: true,\r\n skipped: false,\r\n };\r\n } catch (error) {\r\n return {\r\n ...candidate,\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n}\r\n\r\n", "import { execFileSync } from \"node:child_process\";\r\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\n\r\nconst DEFAULT_DU_TIMEOUT_MS = 2_500;\r\n\r\nfunction directorySizeBytesDu(root: string, timeoutMs = DEFAULT_DU_TIMEOUT_MS): number | null {\r\n if (!existsSync(root)) return 0;\r\n try {\r\n const out = execFileSync(\"du\", [\"-sb\", root], {\r\n encoding: \"utf8\",\r\n timeout: timeoutMs,\r\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\r\n });\r\n const first = out.trim().split(/\\s+/)[0];\r\n const bytes = Number(first);\r\n return Number.isFinite(bytes) && bytes >= 0 ? bytes : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Best-effort directory size. Prefers `du -sb` (fast on large `node_modules`);\r\n * falls back to a capped walk. Returns null when entry cap is exceeded.\r\n */\r\nexport function directorySizeBytes(root: string, maxEntries = 50_000): number | null {\r\n if (!existsSync(root)) return 0;\r\n const duBytes = directorySizeBytesDu(root);\r\n if (duBytes !== null) return duBytes;\r\n let total = 0;\r\n let seen = 0;\r\n const stack: string[] = [root];\r\n while (stack.length > 0) {\r\n const current = stack.pop()!;\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(current);\r\n } catch {\r\n continue;\r\n }\r\n for (const name of entries) {\r\n if (seen++ > maxEntries) return null;\r\n const full = path.join(current, name);\r\n let st;\r\n try {\r\n st = statSync(full);\r\n } catch {\r\n continue;\r\n }\r\n if (st.isDirectory()) stack.push(full);\r\n else total += st.size;\r\n }\r\n }\r\n return total;\r\n}\r\n", "import { existsSync, rmSync } from \"node:fs\";\r\nimport type { CleanupCandidate, CleanupSkipReason } from \"./cleanup-types.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\nimport { harnessWorktreesDir } from \"./paths.js\";\r\nimport { pathHasForeignOwnedEntry } from \"./cleanup-path-ownership.js\";\r\nimport {\r\n HARNESS_ROOT_OWNED_CACHE_RUNBOOK,\r\n resolvePrivilegedCleanupMode,\r\n tryPrivilegedReclaimHarnessCache,\r\n} from \"./cleanup-privileged-remove.js\";\r\n\r\nexport interface RemoveHarnessPathOutcome {\r\n executed: boolean;\r\n skipped: boolean;\r\n skipReason?: CleanupSkipReason;\r\n error?: string;\r\n bytes?: number;\r\n privilegedReclaim?: boolean;\r\n}\r\n\r\ninterface RemoveHarnessGeneratedPathDeps {\r\n removePath?: typeof rmSync;\r\n hasForeignOwnedEntry?: typeof pathHasForeignOwnedEntry;\r\n}\r\n\r\nfunction permissionFailure(error: unknown): boolean {\r\n const code = (error as NodeJS.ErrnoException | undefined)?.code;\r\n return code === \"EACCES\" || code === \"EPERM\";\r\n}\r\n\r\nexport function removeHarnessGeneratedPath(\r\n candidate: CleanupCandidate,\r\n execute: boolean,\r\n deps: RemoveHarnessGeneratedPathDeps = {},\r\n): RemoveHarnessPathOutcome {\r\n if (!existsSync(candidate.path)) {\r\n return { executed: false, skipped: true, skipReason: \"missing_worktree\" };\r\n }\r\n if (!execute) {\r\n return { executed: false, skipped: true, skipReason: \"dry_run\" };\r\n }\r\n\r\n const harnessRoot = candidate.harnessRoot;\r\n const worktreesDir = harnessRoot ? harnessWorktreesDir(harnessRoot) : null;\r\n const bytesBefore = candidate.bytes ?? directorySizeBytes(candidate.path);\r\n const bytesReported = bytesBefore ?? undefined;\r\n const removePath = deps.removePath ?? rmSync;\r\n const hasForeignOwnedEntry = deps.hasForeignOwnedEntry ?? pathHasForeignOwnedEntry;\r\n\r\n try {\r\n removePath(candidate.path, { recursive: true, force: true });\r\n return { executed: true, skipped: false, bytes: bytesReported };\r\n } catch (error) {\r\n if (!permissionFailure(error) || !harnessRoot || !worktreesDir) {\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n\r\n const foreign = hasForeignOwnedEntry(candidate.path);\r\n const mode = resolvePrivilegedCleanupMode();\r\n const shouldTryPrivileged = mode === \"force\" || (mode === \"auto\" && foreign);\r\n if (!shouldTryPrivileged) {\r\n return foreign\r\n ? {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(error as Error).message}; ${HARNESS_ROOT_OWNED_CACHE_RUNBOOK}`,\r\n }\r\n : {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"remove_failed\",\r\n error: (error as Error).message,\r\n };\r\n }\r\n\r\n const reclaim = tryPrivilegedReclaimHarnessCache(candidate.path, harnessRoot, worktreesDir);\r\n if (reclaim.ok && reclaim.method === \"sudo_rm\") {\r\n return {\r\n executed: true,\r\n skipped: false,\r\n bytes: bytesReported,\r\n privilegedReclaim: true,\r\n };\r\n }\r\n\r\n if (reclaim.ok) {\r\n try {\r\n removePath(candidate.path, { recursive: true, force: true });\r\n return {\r\n executed: true,\r\n skipped: false,\r\n bytes: bytesReported,\r\n privilegedReclaim: true,\r\n };\r\n } catch (retryError) {\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(retryError as Error).message}; privileged chown succeeded but rm still failed`,\r\n };\r\n }\r\n }\r\n\r\n return {\r\n executed: false,\r\n skipped: true,\r\n skipReason: \"foreign_owner\",\r\n error: `${(error as Error).message}; privileged reclaim failed: ${reclaim.error}; ${HARNESS_ROOT_OWNED_CACHE_RUNBOOK}`,\r\n };\r\n }\r\n}\r\n", "import { lstatSync, readdirSync } from \"node:fs\";\r\n\r\nexport interface PathOwnershipInfo {\r\n uid: number;\r\n gid: number;\r\n /** True when the entry is not owned by the current process user/group. */\r\n foreign: boolean;\r\n}\r\n\r\nexport function readPathOwnership(targetPath: string): PathOwnershipInfo | null {\r\n try {\r\n const st = lstatSync(targetPath);\r\n const effectiveUid = typeof process.getuid === \"function\" ? process.getuid() : null;\r\n const effectiveGid = typeof process.getgid === \"function\" ? process.getgid() : null;\r\n const foreign =\r\n effectiveUid !== null &&\r\n (st.uid !== effectiveUid || (effectiveGid !== null && st.gid !== effectiveGid));\r\n return { uid: st.uid, gid: st.gid, foreign };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Shallow scan for foreign-owned entries (dependency caches are usually uniform). */\r\nexport function pathHasForeignOwnedEntry(targetPath: string, maxEntries = 32): boolean {\r\n const root = readPathOwnership(targetPath);\r\n if (!root) return false;\r\n if (root.foreign) return true;\r\n try {\r\n const names = readdirSync(targetPath);\r\n let checked = 0;\r\n for (const name of names) {\r\n if (checked >= maxEntries) break;\r\n const child = `${targetPath.replace(/\\/$/, \"\")}/${name}`;\r\n const info = readPathOwnership(child);\r\n checked += 1;\r\n if (info?.foreign) return true;\r\n }\r\n } catch {\r\n // unreadable \u2014 caller will hit EACCES on remove\r\n }\r\n return false;\r\n}\r\n", "import { spawnSync } from \"node:child_process\";\r\nimport path from \"node:path\";\r\nimport { isHarnessGeneratedCachePath } from \"./cleanup-harness-path-validate.js\";\r\n\r\nexport type PrivilegedCleanupMode = \"off\" | \"auto\" | \"force\";\r\n\r\nexport function resolvePrivilegedCleanupMode(): PrivilegedCleanupMode {\r\n const raw = (process.env.KYNVER_CLEANUP_PRIVILEGED ?? \"auto\").trim().toLowerCase();\r\n if (raw === \"0\" || raw === \"false\" || raw === \"off\" || raw === \"no\") return \"off\";\r\n if (raw === \"1\" || raw === \"true\" || raw === \"force\" || raw === \"yes\") return \"force\";\r\n return \"auto\";\r\n}\r\n\r\nfunction runSudoNonInteractive(argv: string[]): { ok: boolean; stderr: string } {\r\n const res = spawnSync(\"sudo\", [\"-n\", ...argv], {\r\n encoding: \"utf8\",\r\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\r\n });\r\n return {\r\n ok: res.status === 0,\r\n stderr: `${res.stderr ?? \"\"}${res.stdout ?? \"\"}`.trim(),\r\n };\r\n}\r\n\r\nexport interface PrivilegedReclaimResult {\r\n ok: boolean;\r\n method?: \"chown_then_rm\" | \"sudo_rm\";\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Reclaim a harness generated cache directory that is not owned by the daemon user.\r\n * Only operates on validated `worktrees/<run>/<worker>/{node_modules,.next,...}` paths.\r\n */\r\nexport function tryPrivilegedReclaimHarnessCache(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): PrivilegedReclaimResult {\r\n if (!isHarnessGeneratedCachePath(targetPath, harnessRoot, worktreesDir)) {\r\n return { ok: false, error: \"path is not an allowed harness generated cache\" };\r\n }\r\n const effectiveUid = typeof process.getuid === \"function\" ? process.getuid() : null;\r\n const effectiveGid = typeof process.getgid === \"function\" ? process.getgid() : null;\r\n if (effectiveUid === null || effectiveGid === null) {\r\n return { ok: false, error: \"privileged reclaim requires POSIX uid/gid\" };\r\n }\r\n\r\n const chown = runSudoNonInteractive([\r\n \"chown\",\r\n \"-R\",\r\n `${effectiveUid}:${effectiveGid}`,\r\n path.resolve(targetPath),\r\n ]);\r\n if (chown.ok) {\r\n return { ok: true, method: \"chown_then_rm\" };\r\n }\r\n\r\n const rm = runSudoNonInteractive([\"rm\", \"-rf\", path.resolve(targetPath)]);\r\n if (rm.ok) {\r\n return { ok: true, method: \"sudo_rm\" };\r\n }\r\n\r\n const detail = chown.stderr || rm.stderr || \"sudo -n failed (password required or not permitted)\";\r\n return {\r\n ok: false,\r\n error: detail,\r\n };\r\n}\r\n\r\nexport const HARNESS_ROOT_OWNED_CACHE_RUNBOOK =\r\n \"Root-owned harness caches require operator reclaim: configure passwordless sudo for chown/rm under ~/.kynver/harness/worktrees, or run `node scripts/reclaim-harness-root-owned-cache.mjs --execute` as the harness owner with sudo available. See docs/runbooks/harness-root-owned-cache-reclaim.md.\";\r\n", "import path from \"node:path\";\r\nimport type { CleanupSkipReason } from \"./cleanup-types.js\";\r\n\r\nfunction isHarnessDependencyCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n cacheDirName: \"node_modules\" | \".next\",\r\n): CleanupSkipReason | null {\r\n const resolved = path.resolve(targetPath);\r\n const suffix = `${path.sep}${cacheDirName}`;\r\n const cachePath = resolved.endsWith(suffix) ? resolved : null;\r\n if (!cachePath) return \"path_outside_harness\";\r\n const rel = path.relative(worktreesDir, cachePath);\r\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return \"path_outside_harness\";\r\n const parts = rel.split(path.sep);\r\n if (parts.length < 3 || parts[parts.length - 1] !== cacheDirName) return \"path_outside_harness\";\r\n if (!resolved.startsWith(path.resolve(harnessRoot))) return \"path_outside_harness\";\r\n return null;\r\n}\r\n\r\nexport function isHarnessNodeModulesPath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, \"node_modules\");\r\n}\r\n\r\nexport function isHarnessNextCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, \".next\");\r\n}\r\n\r\nexport function isHarnessBuildCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): CleanupSkipReason | null {\r\n const resolved = path.resolve(targetPath);\r\n const relToWt = path.relative(worktreesDir, resolved);\r\n if (relToWt.startsWith(\"..\") || path.isAbsolute(relToWt)) return \"path_outside_harness\";\r\n const parts = relToWt.split(path.sep);\r\n if (parts.length < 3) return \"path_outside_harness\";\r\n if (!resolved.startsWith(path.resolve(harnessRoot))) return \"path_outside_harness\";\r\n return null;\r\n}\r\n\r\nexport function isHarnessGeneratedCachePath(\r\n targetPath: string,\r\n harnessRoot: string,\r\n worktreesDir: string,\r\n): boolean {\r\n const resolved = path.resolve(targetPath);\r\n return (\r\n isHarnessNodeModulesPath(resolved, harnessRoot, worktreesDir) === null ||\r\n isHarnessNextCachePath(resolved, harnessRoot, worktreesDir) === null ||\r\n isHarnessBuildCachePath(resolved, harnessRoot, worktreesDir) === null\r\n );\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { HARNESS_BUILD_CACHE_RELATIVE_PATHS } from \"./cleanup-build-cache-paths.js\";\r\nimport { buildWorktreeIndex, type IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\n\r\nexport interface ScanHarnessOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n includeOrphans: boolean;\r\n runIdFilter?: string;\r\n index: Map<string, IndexedWorktree>;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction isPathInside(child: string, parent: string): boolean {\r\n const rel = path.relative(parent, child);\r\n return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\r\n}\r\n\r\nexport function scanNodeModulesCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n const nm = path.join(entry.worktreePath, \"node_modules\");\r\n if (!existsSync(nm)) continue;\r\n const resolved = path.resolve(nm);\r\n if (seen.has(resolved)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_node_modules\",\r\n path: resolved,\r\n bytes: null,\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n const nm = path.join(worktreePath, \"node_modules\");\r\n if (!existsSync(nm)) continue;\r\n const resolved = path.resolve(nm);\r\n if (seen.has(resolved)) continue;\r\n if (!isPathInside(resolved, opts.harnessRoot)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_node_modules\",\r\n path: resolved,\r\n bytes: null,\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nfunction collectBuildCacheForWorktree(\r\n worktreePath: string,\r\n opts: ScanHarnessOptions,\r\n seen: Set<string>,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): CleanupCandidate[] {\r\n const out: CleanupCandidate[] = [];\r\n for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {\r\n if (rel === \".next\") continue;\r\n const target = path.join(worktreePath, rel);\r\n if (!existsSync(target)) continue;\r\n const resolved = path.resolve(target);\r\n if (seen.has(resolved)) continue;\r\n if (!isPathInside(resolved, opts.harnessRoot)) continue;\r\n seen.add(resolved);\r\n out.push({\r\n kind: \"remove_build_cache\",\r\n path: resolved,\r\n bytes: null,\r\n runId: meta.runId,\r\n worker: meta.worker,\r\n repo: meta.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n return out;\r\n}\r\n\r\nexport function scanBuildCacheCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n candidates.push(\r\n ...collectBuildCacheForWorktree(entry.worktreePath, opts, seen, {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n }),\r\n );\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n candidates.push(\r\n ...collectBuildCacheForWorktree(worktreePath, opts, seen, {\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n }),\r\n );\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\nexport function scanWorktreeCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n // Indexed worktrees scan when either an explicit age threshold is set OR the\r\n // operator opted in via `--include-orphans` (the salvage gates in\r\n // `skipWorktreeRemoval` are the primary protection at age 0). Orphan scan\r\n // additionally requires `--include-orphans` and applies the orphan-safety\r\n // check via `assessOrphanWorktreeSafety`.\r\n const indexedEnabled = opts.worktreesAgeMs > 0 || opts.includeOrphans;\r\n const orphanEnabled = opts.includeOrphans;\r\n if (!indexedEnabled && !orphanEnabled) return [];\r\n\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n if (indexedEnabled) {\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n const resolved = entry.worktreePath;\r\n if (!existsSync(resolved)) continue;\r\n if (seen.has(resolved)) continue;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: resolved,\r\n bytes: null,\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n if (!orphanEnabled || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n // Track index entries so we can identify true orphans on disk.\r\n const indexedPaths = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n indexedPaths.add(path.resolve(entry.worktreePath));\r\n }\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n let workerEntries;\r\n try {\r\n workerEntries = readdirSync(runPath, { withFileTypes: true });\r\n } catch {\r\n continue;\r\n }\r\n for (const workerEntry of workerEntries) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.resolve(path.join(runPath, workerEntry.name));\r\n if (seen.has(worktreePath)) continue;\r\n if (indexedPaths.has(worktreePath)) continue;\r\n if (!isPathInside(worktreePath, opts.harnessRoot)) continue;\r\n seen.add(worktreePath);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: worktreePath,\r\n bytes: null,\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n ageMs: pathAgeMs(worktreePath, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupActionKind, CleanupCandidate } from \"./cleanup-types.js\";\r\nimport type { IndexedWorktree } from \"./cleanup-worktree-index.js\";\r\n\r\nconst DEPENDENCY_CACHE_DIRS: Array<{ dirName: string; kind: CleanupActionKind }> = [\r\n { dirName: \"node_modules\", kind: \"remove_node_modules\" },\r\n { dirName: \".next\", kind: \"remove_next_cache\" },\r\n];\r\n\r\nexport interface ScanDependencyCacheOptions {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n nodeModulesAgeMs: number;\r\n includeOrphans?: boolean;\r\n runIdFilter?: string;\r\n index: Map<string, IndexedWorktree>;\r\n now: number;\r\n}\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nfunction isPathInside(child: string, parent: string): boolean {\r\n const rel = path.relative(parent, child);\r\n return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\r\n}\r\n\r\nfunction pushCandidate(\r\n candidates: CleanupCandidate[],\r\n seen: Set<string>,\r\n opts: ScanDependencyCacheOptions,\r\n targetPath: string,\r\n kind: CleanupActionKind,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): void {\r\n if (!existsSync(targetPath)) return;\r\n const resolved = path.resolve(targetPath);\r\n if (seen.has(resolved)) return;\r\n if (!isPathInside(resolved, opts.harnessRoot)) return;\r\n seen.add(resolved);\r\n candidates.push({\r\n kind,\r\n path: resolved,\r\n bytes: null,\r\n harnessRoot: opts.harnessRoot,\r\n runId: meta.runId,\r\n worker: meta.worker,\r\n repo: meta.repo,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n}\r\n\r\nfunction scanWorktreeDependencyCaches(\r\n candidates: CleanupCandidate[],\r\n seen: Set<string>,\r\n opts: ScanDependencyCacheOptions,\r\n worktreePath: string,\r\n meta: { runId?: string; worker?: string; repo?: string },\r\n): void {\r\n for (const entry of DEPENDENCY_CACHE_DIRS) {\r\n pushCandidate(candidates, seen, opts, path.join(worktreePath, entry.dirName), entry.kind, meta);\r\n }\r\n}\r\n\r\n/** Scan indexed + on-disk worktrees for generated dependency caches. */\r\nexport function scanDependencyCacheCandidates(opts: ScanDependencyCacheOptions): CleanupCandidate[] {\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const entry of opts.index.values()) {\r\n if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;\r\n scanWorktreeDependencyCaches(candidates, seen, opts, entry.worktreePath, {\r\n runId: entry.runId,\r\n worker: entry.workerName,\r\n repo: entry.run.repo,\r\n });\r\n }\r\n\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return candidates;\r\n\r\n for (const runEntry of readdirSync(opts.worktreesDir, { withFileTypes: true })) {\r\n if (!runEntry.isDirectory()) continue;\r\n if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;\r\n const runPath = path.join(opts.worktreesDir, runEntry.name);\r\n let workerEntries;\r\n try {\r\n workerEntries = readdirSync(runPath, { withFileTypes: true });\r\n } catch {\r\n continue;\r\n }\r\n for (const workerEntry of workerEntries) {\r\n if (!workerEntry.isDirectory()) continue;\r\n const worktreePath = path.join(runPath, workerEntry.name);\r\n scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, {\r\n runId: runEntry.name,\r\n worker: workerEntry.name,\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import { existsSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { CleanupCandidate } from \"./cleanup-types.js\";\r\nimport { git } from \"./git.js\";\r\nimport type { ScanHarnessOptions } from \"./cleanup-scan.js\";\r\n\r\nfunction pathAgeMs(target: string, now: number): number {\r\n try {\r\n const mtime = statSync(target).mtimeMs;\r\n return Math.max(0, now - mtime);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\ninterface PorcelainWorktree {\r\n path: string;\r\n branch?: string;\r\n head?: string;\r\n bare?: boolean;\r\n}\r\n\r\nfunction parseWorktreePorcelain(output: string): PorcelainWorktree[] {\r\n const records: PorcelainWorktree[] = [];\r\n let current: PorcelainWorktree | null = null;\r\n for (const line of output.split(\"\\n\")) {\r\n if (!line.trim()) continue;\r\n const [key, ...rest] = line.split(\" \");\r\n const value = rest.join(\" \");\r\n if (key === \"worktree\") {\r\n if (current) records.push(current);\r\n current = { path: value };\r\n continue;\r\n }\r\n if (!current) continue;\r\n if (key === \"branch\") current.branch = value;\r\n if (key === \"HEAD\") current.head = value;\r\n if (key === \"bare\") current.bare = true;\r\n }\r\n if (current) records.push(current);\r\n return records;\r\n}\r\n\r\nfunction isUnderWorktreesDir(worktreePath: string, worktreesDir: string): boolean {\r\n const rel = path.relative(path.resolve(worktreesDir), path.resolve(worktreePath));\r\n return rel !== \"\" && !rel.startsWith(\"..\") && !path.isAbsolute(rel);\r\n}\r\n\r\nfunction isCleanWorktree(worktreePath: string, repoRoot: string): boolean {\r\n try {\r\n const porcelain = git(repoRoot, [\"-C\", worktreePath, \"status\", \"--porcelain\"], {\r\n allowFailure: true,\r\n });\r\n return !String(porcelain || \"\").trim();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Secondary git worktrees under the harness layout that are clean but not indexed\r\n * (aborted duplicate attempts). Uses `git worktree remove` during execute.\r\n */\r\nexport function scanDuplicateWorktreeCandidates(opts: ScanHarnessOptions): CleanupCandidate[] {\r\n if (!opts.includeOrphans || !existsSync(opts.worktreesDir)) return [];\r\n\r\n const repos = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n if (entry.run.repo) repos.add(path.resolve(entry.run.repo));\r\n }\r\n\r\n const indexedPaths = new Set<string>();\r\n for (const entry of opts.index.values()) {\r\n indexedPaths.add(path.resolve(entry.worktreePath));\r\n }\r\n\r\n const candidates: CleanupCandidate[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const repoRoot of repos) {\r\n let porcelain: string;\r\n try {\r\n porcelain = git(repoRoot, [\"worktree\", \"list\", \"--porcelain\"], { allowFailure: true });\r\n } catch {\r\n continue;\r\n }\r\n const worktrees = parseWorktreePorcelain(porcelain);\r\n for (const wt of worktrees) {\r\n const resolved = path.resolve(wt.path);\r\n if (resolved === path.resolve(repoRoot)) continue;\r\n if (!isUnderWorktreesDir(resolved, opts.worktreesDir)) continue;\r\n if (indexedPaths.has(resolved)) continue;\r\n if (seen.has(resolved)) continue;\r\n if (!existsSync(resolved)) continue;\r\n if (!isCleanWorktree(resolved, repoRoot)) continue;\r\n\r\n const rel = path.relative(opts.worktreesDir, resolved);\r\n const parts = rel.split(path.sep);\r\n const runId = parts[0];\r\n const worker = parts[1] ?? \"unknown\";\r\n seen.add(resolved);\r\n candidates.push({\r\n kind: \"remove_worktree\",\r\n path: resolved,\r\n bytes: null,\r\n runId,\r\n worker,\r\n repo: repoRoot,\r\n ageMs: pathAgeMs(resolved, opts.now),\r\n });\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n", "import path from \"node:path\";\r\nimport {\r\n getPaths,\r\n listRunRecordsForHarnessRoot,\r\n loadWorker,\r\n runDirectoryAt,\r\n type HarnessRunRecord,\r\n} from \"./run-store.js\";\r\nimport type { HarnessWorkerRecord, RawHarnessWorkerStatus } from \"./status.js\";\r\nimport { readJson, safeSlug } from \"./util.js\";\r\n\r\nexport interface IndexedWorktree {\r\n harnessRoot?: string;\r\n worktreePath: string;\r\n runId: string;\r\n workerName: string;\r\n run: HarnessRunRecord;\r\n worker: HarnessWorkerRecord;\r\n /** Populated lazily via `indexedWorktreeStatus()` during guard evaluation. */\r\n status?: RawHarnessWorkerStatus;\r\n}\r\n\r\nexport function buildWorktreeIndex(): Map<string, IndexedWorktree> {\r\n const { harnessRoot } = getPaths();\r\n return buildWorktreeIndexAt(harnessRoot);\r\n}\r\n\r\nexport function buildWorktreeIndexAt(harnessRoot: string): Map<string, IndexedWorktree> {\r\n const index = new Map<string, IndexedWorktree>();\r\n for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {\r\n for (const name of Object.keys(run.workers || {})) {\r\n const workerPath = path.join(\r\n runDirectoryAt(harnessRoot, run.id),\r\n \"workers\",\r\n safeSlug(name),\r\n \"worker.json\",\r\n );\r\n const worker = readJson<HarnessWorkerRecord | undefined>(workerPath, undefined);\r\n if (!worker?.worktreePath) continue;\r\n index.set(path.resolve(worker.worktreePath), {\r\n harnessRoot,\r\n worktreePath: path.resolve(worker.worktreePath),\r\n runId: run.id,\r\n workerName: name,\r\n run,\r\n worker,\r\n });\r\n }\r\n }\r\n return index;\r\n}\r\n\r\n/** Load worker when index miss but path is known from disk layout. */\r\nexport function loadIndexedWorker(runId: string, workerName: string): HarnessWorkerRecord | null {\r\n try {\r\n return loadWorker(runId, workerName);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n", "import type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport {\r\n DEFAULT_MAX_ACTIONS_PER_SWEEP,\r\n DEFAULT_NODE_MODULES_AGE_MS,\r\n DEFAULT_RUN_DIRECTORIES_AGE_MS,\r\n DEFAULT_TERMINAL_WORKTREES_AGE_MS,\r\n DEFAULT_WORKTREES_AGE_MS,\r\n type HarnessCleanupOptions,\r\n} from \"./cleanup-types.js\";\r\n\r\nfunction envFlag(name: string): boolean {\r\n const v = process.env[name];\r\n return v === \"1\" || v === \"true\" || v === \"yes\";\r\n}\r\n\r\nfunction envMs(name: string, fallback: number): number {\r\n const raw = process.env[name];\r\n if (!raw) return fallback;\r\n const n = Number(raw);\r\n return Number.isFinite(n) && n >= 0 ? n : fallback;\r\n}\r\n\r\nexport interface ResolvedHarnessRetention {\r\n execute: boolean;\r\n finalizeStaleRuns: boolean;\r\n nodeModulesAgeMs: number;\r\n worktreesAgeMs: number;\r\n terminalWorktreesAgeMs: number;\r\n runDirectoriesAgeMs: number;\r\n maxActionsPerSweep: number;\r\n includeOrphans: boolean;\r\n runIdFilter?: string;\r\n accountBytes: boolean;\r\n /** Cap filesystem walk depth per run dir in `harnessStorageSnapshot` (0 = counts only). */\r\n storagePerRunEntryCap: number | null;\r\n /** Per-candidate walk cap when `du` is unavailable (default 2k). */\r\n byteAccountingEntryCap: number;\r\n diskPressure?: boolean;\r\n diskGate?: DispatchNextDiskGateShape;\r\n}\r\n\r\n/** Merge CLI options with operator env defaults (pipeline + `kynver cleanup`). */\r\nexport function resolveHarnessRetention(\r\n options: HarnessCleanupOptions = {},\r\n): ResolvedHarnessRetention {\r\n const execute =\r\n options.execute === true ||\r\n (options.execute !== false && envFlag(\"KYNVER_CLEANUP_EXECUTE\"));\r\n const finalizeStaleRuns =\r\n options.finalizeStaleRuns !== false && !envFlag(\"KYNVER_CLEANUP_SKIP_FINALIZE\");\r\n const nodeModulesAgeMs =\r\n options.nodeModulesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_NODE_MODULES_AGE_MS\", DEFAULT_NODE_MODULES_AGE_MS);\r\n const worktreesAgeMs =\r\n options.worktreesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_WORKTREES_AGE_MS\", 0);\r\n const terminalWorktreesAgeMs =\r\n options.terminalWorktreesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_TERMINAL_WORKTREES_AGE_MS\", DEFAULT_TERMINAL_WORKTREES_AGE_MS);\r\n const runDirectoriesAgeMs =\r\n options.runDirectoriesAgeMs ??\r\n envMs(\"KYNVER_CLEANUP_RUN_DIRECTORIES_AGE_MS\", DEFAULT_RUN_DIRECTORIES_AGE_MS);\r\n const maxActionsPerSweep =\r\n options.maxActionsPerSweep ??\r\n envMs(\"KYNVER_CLEANUP_MAX_ACTIONS_PER_SWEEP\", DEFAULT_MAX_ACTIONS_PER_SWEEP);\r\n const includeOrphans =\r\n options.includeOrphans === true || envFlag(\"KYNVER_CLEANUP_INCLUDE_ORPHANS\");\r\n const scopeAll = envFlag(\"KYNVER_CLEANUP_SCOPE_ALL\") || process.env.KYNVER_CLEANUP_SCOPE === \"all\";\r\n const runIdFilter = scopeAll\r\n ? options.runIdFilter\r\n : options.runIdFilter ?? (process.env.KYNVER_CLEANUP_RUN_ID || undefined);\r\n const accountBytes = options.accountBytes !== false && !envFlag(\"KYNVER_CLEANUP_SKIP_BYTE_ACCOUNTING\");\r\n const storageCapEnv = envMs(\"KYNVER_CLEANUP_STORAGE_ENTRY_CAP\", 2_000);\r\n const storagePerRunEntryCap =\r\n options.storagePerRunEntryCap !== undefined\r\n ? options.storagePerRunEntryCap\r\n : accountBytes\r\n ? storageCapEnv > 0\r\n ? storageCapEnv\r\n : null\r\n : null;\r\n const byteCapEnv = envMs(\"KYNVER_CLEANUP_BYTE_ENTRY_CAP\", 2_000);\r\n const byteAccountingEntryCap =\r\n options.byteAccountingEntryCap ??\r\n (Number.isFinite(byteCapEnv) && byteCapEnv > 0 ? Math.floor(byteCapEnv) : 2_000);\r\n\r\n return {\r\n execute,\r\n finalizeStaleRuns,\r\n nodeModulesAgeMs,\r\n worktreesAgeMs: worktreesAgeMs > 0 ? worktreesAgeMs : 0,\r\n terminalWorktreesAgeMs: terminalWorktreesAgeMs >= 0 ? terminalWorktreesAgeMs : 0,\r\n runDirectoriesAgeMs: runDirectoriesAgeMs >= 0 ? runDirectoriesAgeMs : 0,\r\n maxActionsPerSweep:\r\n Number.isFinite(maxActionsPerSweep) && maxActionsPerSweep > 0\r\n ? Math.floor(maxActionsPerSweep)\r\n : DEFAULT_MAX_ACTIONS_PER_SWEEP,\r\n includeOrphans,\r\n runIdFilter: runIdFilter ? String(runIdFilter) : undefined,\r\n accountBytes,\r\n storagePerRunEntryCap,\r\n byteAccountingEntryCap,\r\n };\r\n}\r\n\r\n/** Pipeline tick: dry-run by default; global scope when `KYNVER_CLEANUP_SCOPE=all`. */\r\nexport function resolvePipelineHarnessRetention(runId?: string): ResolvedHarnessRetention {\r\n const scopeAll = process.env.KYNVER_CLEANUP_SCOPE === \"all\";\r\n const envWorktrees = Number(process.env.KYNVER_CLEANUP_WORKTREES_AGE_MS);\r\n const worktreesAgeMs = scopeAll\r\n ? Number.isFinite(envWorktrees) && envWorktrees > 0\r\n ? envWorktrees\r\n : DEFAULT_WORKTREES_AGE_MS\r\n : Number.isFinite(envWorktrees) && envWorktrees > 0\r\n ? envWorktrees\r\n : 0;\r\n return resolveHarnessRetention({\r\n runIdFilter: scopeAll ? undefined : runId,\r\n worktreesAgeMs,\r\n terminalWorktreesAgeMs: scopeAll ? DEFAULT_TERMINAL_WORKTREES_AGE_MS : undefined,\r\n runDirectoriesAgeMs: scopeAll ? DEFAULT_RUN_DIRECTORIES_AGE_MS : undefined,\r\n includeOrphans: scopeAll ? true : undefined,\r\n finalizeStaleRuns: true,\r\n accountBytes: true,\r\n });\r\n}\r\n", "import { existsSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { gitCapture } from \"./git.js\";\r\nimport { materialWorktreeChanges } from \"./cleanup-guards-helpers.js\";\r\nimport type { CleanupSkipReason } from \"./cleanup-types.js\";\r\n\r\nconst DEFAULT_HEARTBEAT_FRESH_MS = 30 * 60 * 1000;\r\n\r\nexport interface OrphanSafetyInput {\r\n worktreePath: string;\r\n harnessRoot: string;\r\n runId?: string;\r\n workerName?: string;\r\n heartbeatFreshMs?: number;\r\n now?: number;\r\n}\r\n\r\n/**\r\n * Inspect filesystem signals for an orphan worktree (no run/worker.json index entry).\r\n *\r\n * Returns a `CleanupSkipReason` when removal is unsafe, or `null` when the orphan\r\n * appears safe to delete. Conservative on errors \u2014 any unreadable git state or\r\n * unexpected layout returns `pr_or_unmerged_commits` so genuine work is preserved.\r\n */\r\nexport function assessOrphanWorktreeSafety(\r\n input: OrphanSafetyInput,\r\n): CleanupSkipReason | null {\r\n const now = input.now ?? Date.now();\r\n const heartbeatFreshMs = input.heartbeatFreshMs ?? DEFAULT_HEARTBEAT_FRESH_MS;\r\n\r\n if (!existsSync(input.worktreePath)) return null;\r\n\r\n if (input.runId && input.workerName) {\r\n const heartbeatPath = path.join(\r\n input.harnessRoot,\r\n \"runs\",\r\n input.runId,\r\n \"workers\",\r\n input.workerName,\r\n \"heartbeat.jsonl\",\r\n );\r\n try {\r\n const mtime = statSync(heartbeatPath).mtimeMs;\r\n if (now - mtime < heartbeatFreshMs) return \"active_worker\";\r\n } catch {\r\n // No heartbeat \u2014 fine, orphan is fully detached.\r\n }\r\n }\r\n\r\n const gitDir = path.join(input.worktreePath, \".git\");\r\n if (!existsSync(gitDir)) return null;\r\n\r\n const porcelain = gitCapture(input.worktreePath, [\"status\", \"--porcelain\"]);\r\n if (porcelain.status !== 0) return \"pr_or_unmerged_commits\";\r\n const dirtyLines = porcelain.stdout\r\n .split(\"\\n\")\r\n .map((line) => line.trim())\r\n .filter((line) => line.length > 0);\r\n if (materialWorktreeChanges(dirtyLines).length > 0) return \"dirty_worktree\";\r\n\r\n const upstreamAhead = gitCapture(input.worktreePath, [\r\n \"rev-list\",\r\n \"--count\",\r\n \"@{u}..HEAD\",\r\n ]);\r\n if (upstreamAhead.status === 0) {\r\n const count = Number(upstreamAhead.stdout.trim());\r\n if (Number.isFinite(count) && count > 0) return \"pr_or_unmerged_commits\";\r\n }\r\n\r\n const mainAhead = gitCapture(input.worktreePath, [\r\n \"rev-list\",\r\n \"--count\",\r\n \"origin/main..HEAD\",\r\n ]);\r\n if (mainAhead.status !== 0) {\r\n // Upstream may be gone after PR merge; when origin/main is also unreachable, preserve work.\r\n if (upstreamAhead.status !== 0) return \"pr_or_unmerged_commits\";\r\n return null;\r\n }\r\n const mainCount = Number(mainAhead.stdout.trim());\r\n if (Number.isFinite(mainCount) && mainCount > 0) return \"pr_or_unmerged_commits\";\r\n\r\n return null;\r\n}\r\n", "import { existsSync, readdirSync, statSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { harnessWorktreesDir, normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\nimport { directorySizeBytes } from \"./cleanup-dir-size.js\";\r\n\r\nexport interface HarnessStorageSnapshot {\r\n harnessRoot: string;\r\n worktreesDir: string;\r\n /** Sum of per-run directory sizes. `null` when scan exceeded entry cap. */\r\n worktreesBytes: number | null;\r\n /** Top-level run directory count under `worktreesDir`. */\r\n runCount: number;\r\n /** Total worktree (worker) directories across all runs. */\r\n workerCount: number;\r\n /** Earliest run-directory mtime, ISO string. `null` when no runs present. */\r\n oldestRunAt: string | null;\r\n scannedAt: string;\r\n}\r\n\r\ninterface ScanOptions {\r\n harnessRoot?: string;\r\n /** Cap per directorySizeBytes call. Default 50k entries \u2014 keeps the snapshot fast for monitor ticks. Set null/0 to return bytes=null without scanning. */\r\n perRunEntryCap?: number | null;\r\n now?: number;\r\n}\r\n\r\n/**\r\n * Read-only summary of harness worktree storage usage. Surfaced in cleanup\r\n * summaries and consumable by monitor/Command Center to flag disk pressure\r\n * before WSL runs out of space again.\r\n */\r\nexport function harnessStorageSnapshot(opts: ScanOptions = {}): HarnessStorageSnapshot {\r\n const harnessRoot = normalizeHarnessRoot(opts.harnessRoot ?? resolveHarnessRoot());\r\n const worktreesDir = harnessWorktreesDir(harnessRoot);\r\n const now = opts.now ?? Date.now();\r\n const scannedAt = new Date(now).toISOString();\r\n\r\n if (!existsSync(worktreesDir)) {\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: 0,\r\n runCount: 0,\r\n workerCount: 0,\r\n oldestRunAt: null,\r\n scannedAt,\r\n };\r\n }\r\n\r\n let totalBytes: number | null = 0;\r\n let runCount = 0;\r\n let workerCount = 0;\r\n let oldestMs: number | null = null;\r\n\r\n let entries;\r\n try {\r\n entries = readdirSync(worktreesDir, { withFileTypes: true });\r\n } catch {\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: null,\r\n runCount: 0,\r\n workerCount: 0,\r\n oldestRunAt: null,\r\n scannedAt,\r\n };\r\n }\r\n\r\n for (const runEntry of entries) {\r\n if (!runEntry.isDirectory()) continue;\r\n runCount += 1;\r\n const runPath = path.join(worktreesDir, runEntry.name);\r\n try {\r\n const st = statSync(runPath);\r\n oldestMs = oldestMs === null ? st.mtimeMs : Math.min(oldestMs, st.mtimeMs);\r\n } catch {\r\n // ignore unreadable run dir\r\n }\r\n try {\r\n for (const workerEntry of readdirSync(runPath, { withFileTypes: true })) {\r\n if (workerEntry.isDirectory()) workerCount += 1;\r\n }\r\n } catch {\r\n // ignore unreadable run dir\r\n }\r\n if (totalBytes !== null && opts.perRunEntryCap !== null) {\r\n const cap = opts.perRunEntryCap ?? 50_000;\r\n if (cap <= 0) {\r\n totalBytes = null;\r\n } else {\r\n const runBytes = directorySizeBytes(runPath, cap);\r\n if (runBytes === null) totalBytes = null;\r\n else totalBytes += runBytes;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n harnessRoot,\r\n worktreesDir,\r\n worktreesBytes: totalBytes,\r\n runCount,\r\n workerCount,\r\n oldestRunAt: oldestMs === null ? null : new Date(oldestMs).toISOString(),\r\n scannedAt,\r\n };\r\n}\r\n", "import { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport path from \"node:path\";\r\nimport { normalizeHarnessRoot, resolveHarnessRoot } from \"./paths.js\";\r\n\r\n/** Operator-known harness trees that accumulate stale dependency caches. */\r\nexport const WELL_KNOWN_HARNESS_SCAN_ROOTS = [\r\n \"/var/tmp/kynver-harness\",\r\n path.join(homedir(), \".openclaw\", \"harness\"),\r\n] as const;\r\n\r\nfunction addRoot(seen: Set<string>, roots: string[], candidate: string | undefined): void {\r\n if (!candidate?.trim()) return;\r\n const resolved = normalizeHarnessRoot(candidate.trim());\r\n if (seen.has(resolved)) return;\r\n seen.add(resolved);\r\n roots.push(resolved);\r\n}\r\n\r\n/**\r\n * Deduped harness roots to scan for dependency-cache GC. Includes the active\r\n * configured root plus well-known legacy/tmp trees when they exist on disk.\r\n */\r\nfunction shouldScanWellKnownRoots(options: { scanWellKnown?: boolean }): boolean {\r\n if (options.scanWellKnown != null) return options.scanWellKnown;\r\n if (process.env.VITEST === \"true\") return false;\r\n return (\r\n process.env.KYNVER_CLEANUP_SCAN_WELL_KNOWN !== \"0\" &&\r\n ![\"0\", \"false\", \"no\"].includes((process.env.KYNVER_CLEANUP_SCAN_WELL_KNOWN ?? \"\").toLowerCase())\r\n );\r\n}\r\n\r\nexport function resolveHarnessScanRoots(\r\n options: { harnessRoot?: string; scanWellKnown?: boolean } = {},\r\n): string[] {\r\n const seen = new Set<string>();\r\n const roots: string[] = [];\r\n\r\n addRoot(seen, roots, options.harnessRoot ?? resolveHarnessRoot());\r\n\r\n const extra = process.env.KYNVER_CLEANUP_EXTRA_ROOTS?.split(\",\")\r\n .map((part) => part.trim())\r\n .filter(Boolean);\r\n for (const candidate of extra ?? []) addRoot(seen, roots, candidate);\r\n\r\n if (shouldScanWellKnownRoots(options)) {\r\n for (const candidate of WELL_KNOWN_HARNESS_SCAN_ROOTS) {\r\n const resolved = path.resolve(candidate);\r\n if (!seen.has(resolved) && existsSync(resolved)) addRoot(seen, roots, resolved);\r\n }\r\n }\r\n\r\n return roots;\r\n}\r\n", "import type { DispatchNextDiskGateShape } from \"./callbacks.js\";\r\nimport { observeRunnerDiskGate, type ObserveDiskGateInput } from \"./disk-gate.js\";\r\nimport type { ResolvedHarnessRetention } from \"./cleanup-retention-config.js\";\r\nimport { DEFAULT_WORKTREES_AGE_MS } from \"./cleanup-types.js\";\r\n\r\nfunction envFlag(name: string): boolean {\r\n const v = process.env[name];\r\n return v === \"1\" || v === \"true\" || v === \"yes\";\r\n}\r\n\r\nfunction envNumber(name: string, fallback: number): number {\r\n const raw = process.env[name];\r\n if (!raw) return fallback;\r\n const n = Number(raw);\r\n return Number.isFinite(n) ? n : fallback;\r\n}\r\n\r\nexport interface CleanupDiskPressureShape {\r\n diskGate: DispatchNextDiskGateShape;\r\n /** Root filesystem (or override) is at/above the guard threshold. */\r\n pressured: boolean;\r\n maxUsedPercent: number;\r\n}\r\n\r\nexport function observeCleanupDiskPressure(input: ObserveDiskGateInput = {}): CleanupDiskPressureShape {\r\n const diskPath = input.diskPath?.trim() || process.env.KYNVER_DISK_GUARD_PATH?.trim() || \"/\";\r\n const maxUsedPercent = envNumber(\"KYNVER_DISK_GUARD_MAX_USED_PERCENT\", 75);\r\n const diskGate = observeRunnerDiskGate({\r\n ...input,\r\n diskPath,\r\n diskMaxUsedPercent: input.diskMaxUsedPercent ?? maxUsedPercent,\r\n });\r\n let pressured = !diskGate.ok || diskGate.usedPercent >= maxUsedPercent;\r\n\r\n // KYNVER_CLEANUP_DISK_PRESSURE_FORCE=none|pressured overrides the statfs\r\n // verdict. Quota-overlay hosts (managed sandboxes, container quotas) report\r\n // a huge filesystem with little \"available\" space, so the computed\r\n // used-percent reads as critically full even when the workload has plenty\r\n // of headroom \u2014 silently escalating every cleanup into an execute-mode,\r\n // include-orphans sweep. `none` pins pressure off for such hosts (and for\r\n // hermetic tests); `pressured` forces escalation for drills.\r\n const force = process.env.KYNVER_CLEANUP_DISK_PRESSURE_FORCE?.trim().toLowerCase();\r\n if (force === \"none\" || force === \"off\" || force === \"0\") pressured = false;\r\n else if (force === \"pressured\" || force === \"on\" || force === \"1\") pressured = true;\r\n\r\n return { diskGate, pressured, maxUsedPercent };\r\n}\r\n\r\n/**\r\n * Under disk pressure, reclaim generated dependency caches aggressively while\r\n * keeping source worktrees and stricter worktree deletion rules unchanged.\r\n */\r\nexport function applyDiskPressureToRetention(\r\n retention: ResolvedHarnessRetention,\r\n pressure: CleanupDiskPressureShape,\r\n): ResolvedHarnessRetention {\r\n if (!pressure.pressured) return retention;\r\n const executeOnPressure =\r\n retention.execute || !envFlag(\"KYNVER_CLEANUP_DRY_RUN_ON_PRESSURE\");\r\n return {\r\n ...retention,\r\n execute: executeOnPressure,\r\n nodeModulesAgeMs: 0,\r\n // Disk pressure means the current-run-only cleanup scope has already fallen\r\n // behind. Expand the sweep to every known harness root/run, but keep the\r\n // worktree salvage/PR/dirty/live-worker guards in the cleanup pipeline.\r\n runIdFilter: undefined,\r\n includeOrphans: true,\r\n terminalWorktreesAgeMs: 0,\r\n runDirectoriesAgeMs: 0,\r\n worktreesAgeMs: retention.worktreesAgeMs > 0 ? retention.worktreesAgeMs : DEFAULT_WORKTREES_AGE_MS,\r\n diskPressure: true,\r\n diskGate: pressure.diskGate,\r\n };\r\n}\r\n", "/** stderr progress lines so broad cleanup scans do not appear hung before JSON output. */\r\nexport function emitCleanupProgress(phase: string, detail?: string): void {\r\n if (process.env.KYNVER_CLEANUP_QUIET === \"1\") return;\r\n const suffix = detail ? `: ${detail}` : \"\";\r\n console.error(`[kynver cleanup] ${phase}${suffix}`);\r\n}\r\n", "import { gitCapture } from \"./git.js\";\r\n\r\n/** Per-sweep memo for cheap ahead-of-main probes during worktree guard passes. */\r\nexport class CleanupGitRevCache {\r\n private readonly aheadOfMain = new Map<string, number | null>();\r\n\r\n countAheadOfMain(worktreePath: string, base = \"origin/main\"): number | null {\r\n const key = `${worktreePath}\\0${base}`;\r\n if (this.aheadOfMain.has(key)) return this.aheadOfMain.get(key) ?? null;\r\n const result = gitCapture(worktreePath, [\"rev-list\", \"--count\", `${base}..HEAD`]);\r\n if (result.status !== 0) {\r\n this.aheadOfMain.set(key, null);\r\n return null;\r\n }\r\n const count = Number(result.stdout.trim());\r\n const parsed = Number.isFinite(count) ? count : null;\r\n this.aheadOfMain.set(key, parsed);\r\n return parsed;\r\n }\r\n}\r\n", "import { gitStatusShort } from \"./git.js\";\r\n\r\n/** Per-sweep memo so dependency-cache guards do not re-run git per cache dir. */\r\nexport class CleanupGitStatusCache {\r\n private readonly cache = new Map<string, string[]>();\r\n\r\n porcelain(worktreePath: string): string[] {\r\n const resolved = worktreePath;\r\n const cached = this.cache.get(resolved);\r\n if (cached !== undefined) return cached;\r\n const lines = gitStatusShort(resolved);\r\n this.cache.set(resolved, lines);\r\n return lines;\r\n }\r\n}\r\n", "import { deriveTerminalRunStatus } from \"./finalize.js\";\r\nimport type { HarnessRunRecord } from \"./run-store.js\";\r\n\r\n/** Per-sweep memo so worktree guards do not re-derive terminal status for every worker in a run. */\r\nexport class CleanupRunTerminalCache {\r\n private readonly cache = new Map<string, string | null>();\r\n\r\n derive(run: HarnessRunRecord): string | null {\r\n const cached = this.cache.get(run.id);\r\n if (cached !== undefined) return cached;\r\n const derived = deriveTerminalRunStatus(run);\r\n this.cache.set(run.id, derived);\r\n return derived;\r\n }\r\n}\r\n", "import type {\r\n CleanupActionKind,\r\n HarnessCleanupSummary,\r\n HarnessStorageSnapshotShape,\r\n} from \"./cleanup-types.js\";\r\n\r\nconst DEFAULT_SAMPLE_ACTIONS = 12;\r\nconst DEFAULT_SAMPLE_SKIPS = 8;\r\n\r\nexport interface CleanupCompactSummary {\r\n harnessRoot: string;\r\n scanRoots: string[];\r\n dryRun: boolean;\r\n execute: boolean;\r\n scannedAt: string;\r\n finalizedRuns: number;\r\n actionCount: number;\r\n actionKinds: Partial<Record<CleanupActionKind, number>>;\r\n totals: HarnessCleanupSummary[\"totals\"];\r\n storage?: HarnessStorageSnapshotShape;\r\n preservedLivePaths?: HarnessCleanupSummary[\"preservedLivePaths\"];\r\n removedRunDirectories?: number;\r\n sampleActions: Array<{\r\n kind: CleanupActionKind;\r\n path: string;\r\n skipReason?: string;\r\n bytes?: number | null;\r\n runId?: string;\r\n worker?: string;\r\n }>;\r\n sampleSkips: HarnessCleanupSummary[\"skips\"];\r\n}\r\n\r\nfunction tallyActionKinds(actions: HarnessCleanupSummary[\"actions\"]): Partial<Record<CleanupActionKind, number>> {\r\n const counts: Partial<Record<CleanupActionKind, number>> = {};\r\n for (const action of actions) {\r\n counts[action.kind] = (counts[action.kind] ?? 0) + 1;\r\n }\r\n return counts;\r\n}\r\n\r\n/** Operator-facing rollup \u2014 bounded samples, no per-path megabyte JSON dumps. */\r\nexport function buildCleanupCompactSummary(\r\n summary: HarnessCleanupSummary,\r\n options: { maxSampleActions?: number; maxSampleSkips?: number } = {},\r\n): CleanupCompactSummary {\r\n const maxActions = options.maxSampleActions ?? DEFAULT_SAMPLE_ACTIONS;\r\n const maxSkips = options.maxSampleSkips ?? DEFAULT_SAMPLE_SKIPS;\r\n\r\n return {\r\n harnessRoot: summary.harnessRoot,\r\n scanRoots: summary.scanRoots,\r\n dryRun: summary.dryRun,\r\n execute: summary.execute,\r\n scannedAt: summary.scannedAt,\r\n finalizedRuns: summary.finalizedRuns.length,\r\n actionCount: summary.actions.length,\r\n actionKinds: tallyActionKinds(summary.actions),\r\n totals: summary.totals,\r\n ...(summary.storage ? { storage: summary.storage } : {}),\r\n ...(summary.preservedLivePaths?.length ? { preservedLivePaths: summary.preservedLivePaths } : {}),\r\n ...(summary.removedRunDirectories != null ? { removedRunDirectories: summary.removedRunDirectories } : {}),\r\n sampleActions: summary.actions.slice(0, maxActions).map((action) => ({\r\n kind: action.kind,\r\n path: action.path,\r\n ...(action.skipReason ? { skipReason: action.skipReason } : {}),\r\n ...(action.bytes != null ? { bytes: action.bytes } : {}),\r\n ...(action.runId ? { runId: action.runId } : {}),\r\n ...(action.worker ? { worker: action.worker } : {}),\r\n })),\r\n sampleSkips: summary.skips.slice(0, maxSkips),\r\n };\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["path", "existsSync", "readFileSync", "path", "statfsSync", "path", "existsSync", "readdirSync", "statSync", "path", "runDir", "existsSync", "readdirSync", "path", "embedded", "existsSync", "readFileSync", "entry", "tail", "existsSync", "readFileSync", "tidy", "oneLine", "trimOrNull", "hasFinalResult", "tryParseJsonObject", "trimOrNull", "hasFinalResult", "reconciliation", "tail", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "homedir", "path", "existsSync", "homedir", "path", "path", "path", "path", "path", "path", "existsSync", "readdirSync", "statSync", "path", "existsSync", "readdirSync", "statSync", "path", "existsSync", "readdirSync", "statSync", "path", "path", "path", "path", "existsSync", "readdirSync", "runDir", "statSync", "runDir", "path", "existsSync", "statSync", "isActiveHarnessWorker", "path", "statSync", "path", "existsSync", "readdirSync", "existsSync", "rmSync", "existsSync", "readdirSync", "statSync", "path", "existsSync", "readdirSync", "spawnSync", "path", "path", "spawnSync", "path", "existsSync", "existsSync", "rmSync", "existsSync", "readdirSync", "statSync", "path", "pathAgeMs", "statSync", "path", "path", "existsSync", "pathAgeMs", "readdirSync", "existsSync", "readdirSync", "statSync", "path", "pathAgeMs", "isPathInside", "existsSync", "statSync", "path", "pathAgeMs", "path", "path", "finalizeStaleRuns", "existsSync", "statSync", "path", "existsSync", "path", "statSync", "existsSync", "readdirSync", "statSync", "path", "existsSync", "readdirSync", "path", "statSync", "existsSync", "homedir", "path", "envFlag", "path"]
|
|
7
7
|
}
|