open-multi-agent-kit 0.90.9 → 0.91.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +22 -3
  2. package/README.md +14 -1
  3. package/dist/core/agent-session.d.ts +27 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +188 -25
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/command-safety.d.ts.map +1 -1
  8. package/dist/core/command-safety.js +0 -8
  9. package/dist/core/command-safety.js.map +1 -1
  10. package/dist/core/footer-data-provider.d.ts +7 -1
  11. package/dist/core/footer-data-provider.d.ts.map +1 -1
  12. package/dist/core/footer-data-provider.js +12 -0
  13. package/dist/core/footer-data-provider.js.map +1 -1
  14. package/dist/core/index.d.ts +1 -0
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/core/index.js +1 -0
  17. package/dist/core/index.js.map +1 -1
  18. package/dist/core/metrics-sampler.d.ts +20 -0
  19. package/dist/core/metrics-sampler.d.ts.map +1 -1
  20. package/dist/core/metrics-sampler.js +52 -0
  21. package/dist/core/metrics-sampler.js.map +1 -1
  22. package/dist/core/model-registry.d.ts.map +1 -1
  23. package/dist/core/model-registry.js +4 -1
  24. package/dist/core/model-registry.js.map +1 -1
  25. package/dist/core/model-resolver.d.ts.map +1 -1
  26. package/dist/core/model-resolver.js +15 -6
  27. package/dist/core/model-resolver.js.map +1 -1
  28. package/dist/core/provider-resilience.d.ts +51 -0
  29. package/dist/core/provider-resilience.d.ts.map +1 -0
  30. package/dist/core/provider-resilience.js +86 -0
  31. package/dist/core/provider-resilience.js.map +1 -0
  32. package/dist/core/run-journal.d.ts.map +1 -1
  33. package/dist/core/run-journal.js +14 -22
  34. package/dist/core/run-journal.js.map +1 -1
  35. package/dist/core/session-termination.d.ts +8 -2
  36. package/dist/core/session-termination.d.ts.map +1 -1
  37. package/dist/core/session-termination.js +45 -3
  38. package/dist/core/session-termination.js.map +1 -1
  39. package/dist/core/settings-manager.d.ts +30 -0
  40. package/dist/core/settings-manager.d.ts.map +1 -1
  41. package/dist/core/settings-manager.js +17 -0
  42. package/dist/core/settings-manager.js.map +1 -1
  43. package/dist/core/tools/grep.d.ts.map +1 -1
  44. package/dist/core/tools/grep.js +47 -0
  45. package/dist/core/tools/grep.js.map +1 -1
  46. package/dist/core/tools/omp-pure-seams.d.ts +41 -0
  47. package/dist/core/tools/omp-pure-seams.d.ts.map +1 -0
  48. package/dist/core/tools/omp-pure-seams.js +142 -0
  49. package/dist/core/tools/omp-pure-seams.js.map +1 -0
  50. package/dist/core/tools/omp-seam-runtime.d.ts +100 -0
  51. package/dist/core/tools/omp-seam-runtime.d.ts.map +1 -0
  52. package/dist/core/tools/omp-seam-runtime.js +40 -0
  53. package/dist/core/tools/omp-seam-runtime.js.map +1 -0
  54. package/dist/core/tools/read.d.ts.map +1 -1
  55. package/dist/core/tools/read.js +34 -1
  56. package/dist/core/tools/read.js.map +1 -1
  57. package/dist/modes/interactive/components/footer.d.ts +1 -1
  58. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  59. package/dist/modes/interactive/components/footer.js +11 -8
  60. package/dist/modes/interactive/components/footer.js.map +1 -1
  61. package/dist/modes/interactive/theme/omk-aurora-dark.json +80 -0
  62. package/dist/modes/interactive/theme/omk-aurora-light.json +80 -0
  63. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  64. package/dist/modes/interactive/theme/theme.js +5 -0
  65. package/dist/modes/interactive/theme/theme.js.map +1 -1
  66. package/docs/adaptorch-preview.md +1 -1
  67. package/docs/provider-resilience.md +87 -0
  68. package/docs/settings.md +30 -0
  69. package/docs/themes.md +2 -0
  70. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  71. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  72. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  73. package/examples/extensions/gondolin/package-lock.json +2 -2
  74. package/examples/extensions/gondolin/package.json +1 -1
  75. package/examples/extensions/sandbox/package-lock.json +2 -2
  76. package/examples/extensions/sandbox/package.json +1 -1
  77. package/examples/extensions/with-deps/package-lock.json +2 -2
  78. package/examples/extensions/with-deps/package.json +1 -1
  79. package/npm-shrinkwrap.json +22 -13
  80. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"footer-data-provider.js","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ExecFileException, execFile, spawnSync } from \"child_process\";\nimport { existsSync, type FSWatcher, readFileSync, type Stats, statSync, unwatchFile, watchFile } from \"fs\";\nimport { dirname, join, resolve } from \"path\";\nimport { closeWatcher, FS_WATCH_RETRY_DELAY_MS, watchWithErrorHandler } from \"../utils/fs-watch.ts\";\nimport { MetricsSampler } from \"./metrics-sampler.ts\";\nimport { evaluatePiPackageIntake, type PiPackageIntakeSummary } from \"./pi-package-intake.ts\";\n\ntype GitPaths = {\n\trepoDir: string;\n\tcommonGitDir: string;\n\theadPath: string;\n};\n\n/**\n * Find git metadata paths by walking up from cwd.\n * Handles both regular git repos (.git is a directory) and worktrees (.git is a file).\n */\nfunction findGitPaths(cwd: string): GitPaths | null {\n\tlet dir = cwd;\n\twhile (true) {\n\t\tconst gitPath = join(dir, \".git\");\n\t\tif (existsSync(gitPath)) {\n\t\t\ttry {\n\t\t\t\tconst stat = statSync(gitPath);\n\t\t\t\tif (stat.isFile()) {\n\t\t\t\t\tconst content = readFileSync(gitPath, \"utf8\").trim();\n\t\t\t\t\tif (content.startsWith(\"gitdir: \")) {\n\t\t\t\t\t\tconst gitDir = resolve(dir, content.slice(8).trim());\n\t\t\t\t\t\tconst headPath = join(gitDir, \"HEAD\");\n\t\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\t\tconst commonDirPath = join(gitDir, \"commondir\");\n\t\t\t\t\t\tconst commonGitDir = existsSync(commonDirPath)\n\t\t\t\t\t\t\t? resolve(gitDir, readFileSync(commonDirPath, \"utf8\").trim())\n\t\t\t\t\t\t\t: gitDir;\n\t\t\t\t\t\treturn { repoDir: dir, commonGitDir, headPath };\n\t\t\t\t\t}\n\t\t\t\t} else if (stat.isDirectory()) {\n\t\t\t\t\tconst headPath = join(gitPath, \"HEAD\");\n\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\treturn { repoDir: dir, commonGitDir: gitPath, headPath };\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n}\n\n/** Ask git for the current branch. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitSync(repoDir: string): string | null {\n\tconst result = spawnSync(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n\t\tcwd: repoDir,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst branch = result.status === 0 ? result.stdout.trim() : \"\";\n\treturn branch || null;\n}\n\n/** Ask git for the current branch asynchronously. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitAsync(repoDir: string): Promise<string | null> {\n\treturn new Promise((resolvePromise) => {\n\t\texecFile(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"],\n\t\t\t{\n\t\t\t\tcwd: repoDir,\n\t\t\t\tencoding: \"utf8\",\n\t\t\t},\n\t\t\t(error: ExecFileException | null, stdout: string) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tresolvePromise(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst branch = stdout.trim();\n\t\t\t\tresolvePromise(branch || null);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction isWslEnvironment(): boolean {\n\treturn process.platform === \"linux\" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);\n}\n\nfunction isWindowsMountedRepoPath(repoDir: string): boolean {\n\treturn /^\\/mnt\\/[a-z](?:\\/|$)/i.test(repoDir);\n}\n\nfunction shouldPollGitHead(repoDir: string): boolean {\n\treturn isWslEnvironment() && isWindowsMountedRepoPath(repoDir);\n}\n\n/**\n * Provides git branch and extension statuses - data not otherwise accessible to extensions.\n * Token stats, model info available via ctx.sessionManager and ctx.model.\n */\nexport class FooterDataProvider {\n\tprivate cwd: string;\n\tprivate static readonly WATCH_DEBOUNCE_MS = 500;\n\n\tprivate extensionStatuses = new Map<string, string>();\n\tprivate cachedBranch: string | null | undefined = undefined;\n\tprivate gitPaths: GitPaths | null | undefined = undefined;\n\tprivate headWatcher: FSWatcher | null = null;\n\tprivate headWatchFilePath: string | null = null;\n\tprivate headWatchFileListener: ((current: Stats, previous: Stats) => void) | null = null;\n\tprivate reftableWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListPath: string | null = null;\n\tprivate branchChangeCallbacks = new Set<() => void>();\n\tprivate availableProviderCount = 0;\n\tprivate refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate gitWatcherRetryTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate refreshInFlight = false;\n\tprivate refreshPending = false;\n\tprivate disposed = false;\n\tprivate metricsSampler: MetricsSampler;\n\n\tconstructor(cwd: string) {\n\t\tthis.cwd = cwd;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.metricsSampler = new MetricsSampler();\n\t\tthis.metricsSampler.start();\n\t}\n\n\t/** Current git branch, null if not in repo, \"detached\" if detached HEAD */\n\tgetGitBranch(): string | null {\n\t\tif (this.cachedBranch === undefined) {\n\t\t\tthis.cachedBranch = this.resolveGitBranchSync();\n\t\t}\n\t\treturn this.cachedBranch;\n\t}\n\n\t/** Extension status texts set via ctx.ui.setStatus() */\n\tgetExtensionStatuses(): ReadonlyMap<string, string> {\n\t\treturn this.extensionStatuses;\n\t}\n\n\t/** Subscribe to git branch changes. Returns unsubscribe function. */\n\tonBranchChange(callback: () => void): () => void {\n\t\tthis.branchChangeCallbacks.add(callback);\n\t\treturn () => this.branchChangeCallbacks.delete(callback);\n\t}\n\n\t/** Internal: set extension status */\n\tsetExtensionStatus(key: string, text: string | undefined): void {\n\t\tif (text === undefined) {\n\t\t\tthis.extensionStatuses.delete(key);\n\t\t} else {\n\t\t\tthis.extensionStatuses.set(key, text);\n\t\t}\n\t}\n\n\t/** Internal: clear extension statuses */\n\tclearExtensionStatuses(): void {\n\t\tthis.extensionStatuses.clear();\n\t}\n\n\t/** Number of unique providers with available models (for footer display) */\n\tgetAvailableProviderCount(): number {\n\t\treturn this.availableProviderCount;\n\t}\n\n\t/** Most recent process CPU percent (0-100), or `null` if not yet sampled. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.metricsSampler.getCpuPercent();\n\t}\n\n\t/** Most recent process RSS memory size in bytes, or `null` if not yet sampled. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.metricsSampler.getMemoryRssBytes();\n\t}\n\n\tgetPackageIntakeSummary(): PiPackageIntakeSummary {\n\t\treturn evaluatePiPackageIntake().summary;\n\t}\n\n\t/** Internal: update available provider count */\n\tsetAvailableProviderCount(count: number): void {\n\t\tthis.availableProviderCount = count;\n\t}\n\n\tsetCwd(cwd: string): void {\n\t\tif (this.cwd === cwd) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cwd = cwd;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.cachedBranch = undefined;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.notifyBranchChange();\n\t}\n\n\t/** Internal: cleanup */\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.branchChangeCallbacks.clear();\n\t\tthis.metricsSampler.stop();\n\t}\n\n\tprivate notifyBranchChange(): void {\n\t\tfor (const cb of this.branchChangeCallbacks) cb();\n\t}\n\n\tprivate scheduleRefresh(): void {\n\t\tif (this.disposed || this.refreshTimer) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.refreshTimer = setTimeout(() => {\n\t\t\tthis.refreshTimer = null;\n\t\t\tvoid this.refreshGitBranchAsync();\n\t\t}, FooterDataProvider.WATCH_DEBOUNCE_MS);\n\t}\n\n\tprivate async refreshGitBranchAsync(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.refreshInFlight = true;\n\t\ttry {\n\t\t\tconst nextBranch = await this.resolveGitBranchAsync();\n\t\t\tif (this.disposed) return;\n\t\t\tif (this.cachedBranch !== undefined && this.cachedBranch !== nextBranch) {\n\t\t\t\tthis.cachedBranch = nextBranch;\n\t\t\t\tthis.notifyBranchChange();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.cachedBranch = nextBranch;\n\t\t} finally {\n\t\t\tthis.refreshInFlight = false;\n\t\t\tif (this.refreshPending && !this.disposed) {\n\t\t\t\tthis.refreshPending = false;\n\t\t\t\tthis.scheduleRefresh();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate resolveGitBranchSync(): string | null {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\" ? (resolveBranchWithGitSync(this.gitPaths.repoDir) ?? \"detached\") : branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async resolveGitBranchAsync(): Promise<string | null> {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\"\n\t\t\t\t\t? ((await resolveBranchWithGitAsync(this.gitPaths.repoDir)) ?? \"detached\")\n\t\t\t\t\t: branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate clearGitWatchers(): void {\n\t\tcloseWatcher(this.headWatcher);\n\t\tthis.headWatcher = null;\n\t\tif (this.headWatchFilePath && this.headWatchFileListener) {\n\t\t\tunwatchFile(this.headWatchFilePath, this.headWatchFileListener);\n\t\t\tthis.headWatchFilePath = null;\n\t\t\tthis.headWatchFileListener = null;\n\t\t}\n\t\tcloseWatcher(this.reftableWatcher);\n\t\tthis.reftableWatcher = null;\n\t\tcloseWatcher(this.reftableTablesListWatcher);\n\t\tthis.reftableTablesListWatcher = null;\n\t\tif (this.reftableTablesListPath) {\n\t\t\tunwatchFile(this.reftableTablesListPath);\n\t\t\tthis.reftableTablesListPath = null;\n\t\t}\n\t\tif (this.gitWatcherRetryTimer) {\n\t\t\tclearTimeout(this.gitWatcherRetryTimer);\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t}\n\t}\n\n\tprivate scheduleGitWatcherRetry(): void {\n\t\tif (this.disposed || this.gitWatcherRetryTimer) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gitWatcherRetryTimer = setTimeout(() => {\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t\tthis.setupGitWatcher();\n\t\t}, FS_WATCH_RETRY_DELAY_MS);\n\t}\n\n\tprivate handleGitWatcherError(): void {\n\t\tthis.clearGitWatchers();\n\t\tthis.scheduleGitWatcherRetry();\n\t}\n\n\tprivate setupGitWatcher(): void {\n\t\tthis.clearGitWatchers();\n\t\tif (!this.gitPaths) return;\n\n\t\tconst pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);\n\n\t\t// Watch the directory containing HEAD, not HEAD itself.\n\t\t// Git uses atomic writes (write temp, rename over HEAD), which changes the inode.\n\t\t// fs.watch on a file stops working after the inode changes.\n\t\tthis.headWatcher = watchWithErrorHandler(\n\t\t\tdirname(this.gitPaths.headPath),\n\t\t\t(_eventType, filename) => {\n\t\t\t\tif (!filename || filename === \"HEAD\") {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.handleGitWatcherError(),\n\t\t);\n\t\tif (pollGitHead) {\n\t\t\tthis.headWatchFilePath = this.gitPaths.headPath;\n\t\t\tthis.headWatchFileListener = (current, previous) => {\n\t\t\t\tif (\n\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t) {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t};\n\t\t\twatchFile(this.headWatchFilePath, { interval: 1000 }, this.headWatchFileListener);\n\t\t}\n\t\tif (!this.headWatcher && !pollGitHead) {\n\t\t\treturn;\n\t\t}\n\n\t\t// In reftable repos, branch switches update files in the reftable directory\n\t\t// instead of HEAD. Watch it separately so the footer picks up those changes.\n\t\tconst reftableDir = join(this.gitPaths.commonGitDir, \"reftable\");\n\t\tif (existsSync(reftableDir)) {\n\t\t\tthis.reftableWatcher = watchWithErrorHandler(\n\t\t\t\treftableDir,\n\t\t\t\t() => {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t},\n\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t);\n\t\t\tif (!this.reftableWatcher) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tablesListPath = join(reftableDir, \"tables.list\");\n\t\t\tif (existsSync(tablesListPath)) {\n\t\t\t\tthis.reftableTablesListPath = tablesListPath;\n\t\t\t\tthis.reftableTablesListWatcher = watchWithErrorHandler(\n\t\t\t\t\ttablesListPath,\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t},\n\t\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t\t);\n\t\t\t\tif (!this.reftableTablesListWatcher) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\twatchFile(tablesListPath, { interval: 250 }, (current, previous) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Read-only view for extensions - excludes setExtensionStatus, setAvailableProviderCount and dispose */\nexport type ReadonlyFooterDataProvider = Pick<\n\tFooterDataProvider,\n\t| \"getGitBranch\"\n\t| \"getExtensionStatuses\"\n\t| \"getAvailableProviderCount\"\n\t| \"onBranchChange\"\n\t| \"getCpuPercent\"\n\t| \"getMemoryRssBytes\"\n\t| \"getPackageIntakeSummary\"\n>;\n"]}
1
+ {"version":3,"file":"footer-data-provider.js","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ExecFileException, execFile, spawnSync } from \"child_process\";\nimport { existsSync, type FSWatcher, readFileSync, type Stats, statSync, unwatchFile, watchFile } from \"fs\";\nimport { dirname, join, resolve } from \"path\";\nimport { closeWatcher, FS_WATCH_RETRY_DELAY_MS, watchWithErrorHandler } from \"../utils/fs-watch.ts\";\nimport { MetricsSampler } from \"./metrics-sampler.ts\";\nimport { evaluatePiPackageIntake, type PiPackageIntakeSummary } from \"./pi-package-intake.ts\";\n\ntype GitPaths = {\n\trepoDir: string;\n\tcommonGitDir: string;\n\theadPath: string;\n};\n\n/**\n * Find git metadata paths by walking up from cwd.\n * Handles both regular git repos (.git is a directory) and worktrees (.git is a file).\n */\nfunction findGitPaths(cwd: string): GitPaths | null {\n\tlet dir = cwd;\n\twhile (true) {\n\t\tconst gitPath = join(dir, \".git\");\n\t\tif (existsSync(gitPath)) {\n\t\t\ttry {\n\t\t\t\tconst stat = statSync(gitPath);\n\t\t\t\tif (stat.isFile()) {\n\t\t\t\t\tconst content = readFileSync(gitPath, \"utf8\").trim();\n\t\t\t\t\tif (content.startsWith(\"gitdir: \")) {\n\t\t\t\t\t\tconst gitDir = resolve(dir, content.slice(8).trim());\n\t\t\t\t\t\tconst headPath = join(gitDir, \"HEAD\");\n\t\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\t\tconst commonDirPath = join(gitDir, \"commondir\");\n\t\t\t\t\t\tconst commonGitDir = existsSync(commonDirPath)\n\t\t\t\t\t\t\t? resolve(gitDir, readFileSync(commonDirPath, \"utf8\").trim())\n\t\t\t\t\t\t\t: gitDir;\n\t\t\t\t\t\treturn { repoDir: dir, commonGitDir, headPath };\n\t\t\t\t\t}\n\t\t\t\t} else if (stat.isDirectory()) {\n\t\t\t\t\tconst headPath = join(gitPath, \"HEAD\");\n\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\treturn { repoDir: dir, commonGitDir: gitPath, headPath };\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n}\n\n/** Ask git for the current branch. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitSync(repoDir: string): string | null {\n\tconst result = spawnSync(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n\t\tcwd: repoDir,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst branch = result.status === 0 ? result.stdout.trim() : \"\";\n\treturn branch || null;\n}\n\n/** Ask git for the current branch asynchronously. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitAsync(repoDir: string): Promise<string | null> {\n\treturn new Promise((resolvePromise) => {\n\t\texecFile(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"],\n\t\t\t{\n\t\t\t\tcwd: repoDir,\n\t\t\t\tencoding: \"utf8\",\n\t\t\t},\n\t\t\t(error: ExecFileException | null, stdout: string) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tresolvePromise(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst branch = stdout.trim();\n\t\t\t\tresolvePromise(branch || null);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction isWslEnvironment(): boolean {\n\treturn process.platform === \"linux\" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);\n}\n\nfunction isWindowsMountedRepoPath(repoDir: string): boolean {\n\treturn /^\\/mnt\\/[a-z](?:\\/|$)/i.test(repoDir);\n}\n\nfunction shouldPollGitHead(repoDir: string): boolean {\n\treturn isWslEnvironment() && isWindowsMountedRepoPath(repoDir);\n}\n\n/**\n * Provides git branch and extension statuses - data not otherwise accessible to extensions.\n * Token stats, model info available via ctx.sessionManager and ctx.model.\n */\nexport class FooterDataProvider {\n\tprivate cwd: string;\n\tprivate static readonly WATCH_DEBOUNCE_MS = 500;\n\n\tprivate extensionStatuses = new Map<string, string>();\n\tprivate cachedBranch: string | null | undefined = undefined;\n\tprivate gitPaths: GitPaths | null | undefined = undefined;\n\tprivate headWatcher: FSWatcher | null = null;\n\tprivate headWatchFilePath: string | null = null;\n\tprivate headWatchFileListener: ((current: Stats, previous: Stats) => void) | null = null;\n\tprivate reftableWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListPath: string | null = null;\n\tprivate branchChangeCallbacks = new Set<() => void>();\n\tprivate availableProviderCount = 0;\n\tprivate refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate gitWatcherRetryTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate refreshInFlight = false;\n\tprivate refreshPending = false;\n\tprivate disposed = false;\n\tprivate metricsSampler: MetricsSampler;\n\n\tconstructor(cwd: string) {\n\t\tthis.cwd = cwd;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.metricsSampler = new MetricsSampler();\n\t\tthis.metricsSampler.start();\n\t}\n\n\t/** Current git branch, null if not in repo, \"detached\" if detached HEAD */\n\tgetGitBranch(): string | null {\n\t\tif (this.cachedBranch === undefined) {\n\t\t\tthis.cachedBranch = this.resolveGitBranchSync();\n\t\t}\n\t\treturn this.cachedBranch;\n\t}\n\n\t/** Extension status texts set via ctx.ui.setStatus() */\n\tgetExtensionStatuses(): ReadonlyMap<string, string> {\n\t\treturn this.extensionStatuses;\n\t}\n\n\t/** Subscribe to git branch changes. Returns unsubscribe function. */\n\tonBranchChange(callback: () => void): () => void {\n\t\tthis.branchChangeCallbacks.add(callback);\n\t\treturn () => this.branchChangeCallbacks.delete(callback);\n\t}\n\n\t/** Internal: set extension status */\n\tsetExtensionStatus(key: string, text: string | undefined): void {\n\t\tif (text === undefined) {\n\t\t\tthis.extensionStatuses.delete(key);\n\t\t} else {\n\t\t\tthis.extensionStatuses.set(key, text);\n\t\t}\n\t}\n\n\t/** Internal: clear extension statuses */\n\tclearExtensionStatuses(): void {\n\t\tthis.extensionStatuses.clear();\n\t}\n\n\t/** Number of unique providers with available models (for footer display) */\n\tgetAvailableProviderCount(): number {\n\t\treturn this.availableProviderCount;\n\t}\n\n\t/** Most recent process CPU percent (0-100), or `null` if not yet sampled. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.metricsSampler.getCpuPercent();\n\t}\n\n\t/** Most recent process RSS memory size in bytes, or `null` if not yet sampled. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.metricsSampler.getMemoryRssBytes();\n\t}\n\n\t/** System-wide CPU busy percent (0-100), or `null` if not yet sampled. */\n\tgetSystemCpuPercent(): number | null {\n\t\treturn this.metricsSampler.getSystemCpuPercent();\n\t}\n\n\t/** System-wide used memory in bytes, or `null` if not yet sampled. */\n\tgetSystemMemoryUsedBytes(): number | null {\n\t\treturn this.metricsSampler.getSystemMemoryUsedBytes();\n\t}\n\n\t/** System total physical memory in bytes, or `null` if not yet sampled. */\n\tgetSystemMemoryTotalBytes(): number | null {\n\t\treturn this.metricsSampler.getSystemMemoryTotalBytes();\n\t}\n\n\tgetPackageIntakeSummary(): PiPackageIntakeSummary {\n\t\treturn evaluatePiPackageIntake().summary;\n\t}\n\n\t/** Internal: update available provider count */\n\tsetAvailableProviderCount(count: number): void {\n\t\tthis.availableProviderCount = count;\n\t}\n\n\tsetCwd(cwd: string): void {\n\t\tif (this.cwd === cwd) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cwd = cwd;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.cachedBranch = undefined;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.notifyBranchChange();\n\t}\n\n\t/** Internal: cleanup */\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.branchChangeCallbacks.clear();\n\t\tthis.metricsSampler.stop();\n\t}\n\n\tprivate notifyBranchChange(): void {\n\t\tfor (const cb of this.branchChangeCallbacks) cb();\n\t}\n\n\tprivate scheduleRefresh(): void {\n\t\tif (this.disposed || this.refreshTimer) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.refreshTimer = setTimeout(() => {\n\t\t\tthis.refreshTimer = null;\n\t\t\tvoid this.refreshGitBranchAsync();\n\t\t}, FooterDataProvider.WATCH_DEBOUNCE_MS);\n\t}\n\n\tprivate async refreshGitBranchAsync(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.refreshInFlight = true;\n\t\ttry {\n\t\t\tconst nextBranch = await this.resolveGitBranchAsync();\n\t\t\tif (this.disposed) return;\n\t\t\tif (this.cachedBranch !== undefined && this.cachedBranch !== nextBranch) {\n\t\t\t\tthis.cachedBranch = nextBranch;\n\t\t\t\tthis.notifyBranchChange();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.cachedBranch = nextBranch;\n\t\t} finally {\n\t\t\tthis.refreshInFlight = false;\n\t\t\tif (this.refreshPending && !this.disposed) {\n\t\t\t\tthis.refreshPending = false;\n\t\t\t\tthis.scheduleRefresh();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate resolveGitBranchSync(): string | null {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\" ? (resolveBranchWithGitSync(this.gitPaths.repoDir) ?? \"detached\") : branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async resolveGitBranchAsync(): Promise<string | null> {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\"\n\t\t\t\t\t? ((await resolveBranchWithGitAsync(this.gitPaths.repoDir)) ?? \"detached\")\n\t\t\t\t\t: branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate clearGitWatchers(): void {\n\t\tcloseWatcher(this.headWatcher);\n\t\tthis.headWatcher = null;\n\t\tif (this.headWatchFilePath && this.headWatchFileListener) {\n\t\t\tunwatchFile(this.headWatchFilePath, this.headWatchFileListener);\n\t\t\tthis.headWatchFilePath = null;\n\t\t\tthis.headWatchFileListener = null;\n\t\t}\n\t\tcloseWatcher(this.reftableWatcher);\n\t\tthis.reftableWatcher = null;\n\t\tcloseWatcher(this.reftableTablesListWatcher);\n\t\tthis.reftableTablesListWatcher = null;\n\t\tif (this.reftableTablesListPath) {\n\t\t\tunwatchFile(this.reftableTablesListPath);\n\t\t\tthis.reftableTablesListPath = null;\n\t\t}\n\t\tif (this.gitWatcherRetryTimer) {\n\t\t\tclearTimeout(this.gitWatcherRetryTimer);\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t}\n\t}\n\n\tprivate scheduleGitWatcherRetry(): void {\n\t\tif (this.disposed || this.gitWatcherRetryTimer) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gitWatcherRetryTimer = setTimeout(() => {\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t\tthis.setupGitWatcher();\n\t\t}, FS_WATCH_RETRY_DELAY_MS);\n\t}\n\n\tprivate handleGitWatcherError(): void {\n\t\tthis.clearGitWatchers();\n\t\tthis.scheduleGitWatcherRetry();\n\t}\n\n\tprivate setupGitWatcher(): void {\n\t\tthis.clearGitWatchers();\n\t\tif (!this.gitPaths) return;\n\n\t\tconst pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);\n\n\t\t// Watch the directory containing HEAD, not HEAD itself.\n\t\t// Git uses atomic writes (write temp, rename over HEAD), which changes the inode.\n\t\t// fs.watch on a file stops working after the inode changes.\n\t\tthis.headWatcher = watchWithErrorHandler(\n\t\t\tdirname(this.gitPaths.headPath),\n\t\t\t(_eventType, filename) => {\n\t\t\t\tif (!filename || filename === \"HEAD\") {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.handleGitWatcherError(),\n\t\t);\n\t\tif (pollGitHead) {\n\t\t\tthis.headWatchFilePath = this.gitPaths.headPath;\n\t\t\tthis.headWatchFileListener = (current, previous) => {\n\t\t\t\tif (\n\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t) {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t};\n\t\t\twatchFile(this.headWatchFilePath, { interval: 1000 }, this.headWatchFileListener);\n\t\t}\n\t\tif (!this.headWatcher && !pollGitHead) {\n\t\t\treturn;\n\t\t}\n\n\t\t// In reftable repos, branch switches update files in the reftable directory\n\t\t// instead of HEAD. Watch it separately so the footer picks up those changes.\n\t\tconst reftableDir = join(this.gitPaths.commonGitDir, \"reftable\");\n\t\tif (existsSync(reftableDir)) {\n\t\t\tthis.reftableWatcher = watchWithErrorHandler(\n\t\t\t\treftableDir,\n\t\t\t\t() => {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t},\n\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t);\n\t\t\tif (!this.reftableWatcher) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tablesListPath = join(reftableDir, \"tables.list\");\n\t\t\tif (existsSync(tablesListPath)) {\n\t\t\t\tthis.reftableTablesListPath = tablesListPath;\n\t\t\t\tthis.reftableTablesListWatcher = watchWithErrorHandler(\n\t\t\t\t\ttablesListPath,\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t},\n\t\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t\t);\n\t\t\t\tif (!this.reftableTablesListWatcher) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\twatchFile(tablesListPath, { interval: 250 }, (current, previous) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Read-only view for extensions - excludes setExtensionStatus, setAvailableProviderCount and dispose */\nexport type ReadonlyFooterDataProvider = Pick<\n\tFooterDataProvider,\n\t| \"getGitBranch\"\n\t| \"getExtensionStatuses\"\n\t| \"getAvailableProviderCount\"\n\t| \"onBranchChange\"\n\t| \"getCpuPercent\"\n\t| \"getMemoryRssBytes\"\n\t| \"getSystemCpuPercent\"\n\t| \"getSystemMemoryUsedBytes\"\n\t| \"getSystemMemoryTotalBytes\"\n\t| \"getPackageIntakeSummary\"\n>;\n"]}
@@ -10,6 +10,7 @@ export { applyContextCacheInvalidation, type ContextCacheInvalidationEvent, type
10
10
  export { computeReservedTokenBudget, estimateToolResultReserve, ReservedTokenBudgetError, } from "./context-budget-reserved-tokens.ts";
11
11
  export { createEventBus, type EventBus, type EventBusController } from "./event-bus.ts";
12
12
  export { type AgentEndEvent, type AgentStartEvent, type AgentToolResult, type AgentToolUpdateCallback, type BeforeAgentStartEvent, type BeforeAgentStartEventResult, type BuildSystemPromptOptions, type ContextEvent, defineTool, discoverAndLoadExtensions, type ExecOptions, type ExecResult, type Extension, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext, type ExtensionError, type ExtensionEvent, type ExtensionFactory, type ExtensionFlag, type ExtensionHandler, ExtensionRunner, type ExtensionShortcut, type ExtensionUIContext, type LoadExtensionsResult, type MessageRenderer, type RegisteredCommand, type SessionBeforeCompactEvent, type SessionBeforeForkEvent, type SessionBeforeSwitchEvent, type SessionBeforeTreeEvent, type SessionCompactEvent, type SessionShutdownEvent, type SessionStartEvent, type SessionTreeEvent, type ToolCallEvent, type ToolCallEventResult, type ToolDefinition, type ToolRenderResultOptions, type ToolResultEvent, type TurnEndEvent, type TurnStartEvent, type WorkingIndicatorOptions, } from "./extensions/index.ts";
13
+ export { DEFAULT_PROVIDER_RESILIENCE, DEFAULT_SAFETY_FAILOVER_CANDIDATES, type FailoverCandidate, isContentSafetyStopMessage, isOrphanToolCallIdError, isStickySafetyModel, isTransientProviderErrorMessage, type ProviderResilienceSettings, pickFailoverCandidate, resolveFailoverCandidates, resolveProviderResilience, STICKY_SAFETY_MODEL_RE, stickySafetyBlockMessage, } from "./provider-resilience.ts";
13
14
  export { appendRunJournalRecordDurably, type OpenRunJournalStoreOptions, type RunJournalQuarantineReport, RunJournalStore, RunJournalStoreCorruptionError, writeQuarantineBytesDurably, } from "./run-journal-store.ts";
14
15
  export { classifySessionTermination, formatSessionTermination, type SessionTermination, type SessionTerminationCause, SessionTerminationError, type SessionTerminationKind, } from "./session-termination.ts";
15
16
  export { createSyntheticSourceInfo } from "./source-info.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Core modules shared between all run modes.\n */\n\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n\ttype SessionTranscriptRepair,\n} from \"./agent-session.ts\";\nexport {\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\ttype CreateAgentSessionRuntimeResult,\n\tcreateAgentSessionRuntime,\n} from \"./agent-session-runtime.ts\";\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\nexport { type BashExecutorOptions, type BashResult, executeBashWithOperations } from \"./bash-executor.ts\";\nexport {\n\ttype CompactionBarrierResult,\n\ttype CompactionCommitDecision,\n\ttype CompactionEnvelope,\n\ttype CompactionHysteresisConfig,\n\ttype CompactionHysteresisState,\n\ttype CompactionResult,\n\ttype CompactionTransaction,\n\tcreateCompactionEnvelope,\n\tcreateCompactionHysteresisConfig,\n\tcreateCompactionHysteresisState,\n\tcreateCompactionSourceIdentity,\n\tcreateCompactionTransaction,\n\tcreateSessionRevisionToken,\n\tdecideCompactionCommit,\n\tevaluateCompactionBarrier,\n\tstepCompactionHysteresis,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/index.ts\";\nexport {\n\tapplyContextCacheInvalidation,\n\ttype ContextCacheInvalidationEvent,\n\ttype ContextCacheInvalidationSnapshot,\n\tcreateContextCacheInvalidationSnapshot,\n\tplanPromptContextBudgetV2,\n} from \"./context-budget-governor-v2.ts\";\nexport {\n\tcomputeReservedTokenBudget,\n\testimateToolResultReserve,\n\tReservedTokenBudgetError,\n} from \"./context-budget-reserved-tokens.ts\";\nexport { createEventBus, type EventBus, type EventBusController } from \"./event-bus.ts\";\n// Extensions system\nexport {\n\ttype AgentEndEvent,\n\ttype AgentStartEvent,\n\ttype AgentToolResult,\n\ttype AgentToolUpdateCallback,\n\ttype BeforeAgentStartEvent,\n\ttype BeforeAgentStartEventResult,\n\ttype BuildSystemPromptOptions,\n\ttype ContextEvent,\n\tdefineTool,\n\tdiscoverAndLoadExtensions,\n\ttype ExecOptions,\n\ttype ExecResult,\n\ttype Extension,\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n\ttype ExtensionError,\n\ttype ExtensionEvent,\n\ttype ExtensionFactory,\n\ttype ExtensionFlag,\n\ttype ExtensionHandler,\n\tExtensionRunner,\n\ttype ExtensionShortcut,\n\ttype ExtensionUIContext,\n\ttype LoadExtensionsResult,\n\ttype MessageRenderer,\n\ttype RegisteredCommand,\n\ttype SessionBeforeCompactEvent,\n\ttype SessionBeforeForkEvent,\n\ttype SessionBeforeSwitchEvent,\n\ttype SessionBeforeTreeEvent,\n\ttype SessionCompactEvent,\n\ttype SessionShutdownEvent,\n\ttype SessionStartEvent,\n\ttype SessionTreeEvent,\n\ttype ToolCallEvent,\n\ttype ToolCallEventResult,\n\ttype ToolDefinition,\n\ttype ToolRenderResultOptions,\n\ttype ToolResultEvent,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\ttype WorkingIndicatorOptions,\n} from \"./extensions/index.ts\";\nexport {\n\tappendRunJournalRecordDurably,\n\ttype OpenRunJournalStoreOptions,\n\ttype RunJournalQuarantineReport,\n\tRunJournalStore,\n\tRunJournalStoreCorruptionError,\n\twriteQuarantineBytesDurably,\n} from \"./run-journal-store.ts\";\nexport {\n\tclassifySessionTermination,\n\tformatSessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n\tSessionTerminationError,\n\ttype SessionTerminationKind,\n} from \"./session-termination.ts\";\nexport { createSyntheticSourceInfo } from \"./source-info.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,uBAAuB,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,mBAAmB,EACnB,KAAK,gCAAgC,EACrC,KAAK,+BAA+B,EACpC,yBAAyB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACN,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EACzB,KAAK,qCAAqC,EAC1C,KAAK,iCAAiC,EACtC,8BAA8B,EAC9B,0BAA0B,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,UAAU,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC1G,OAAO,EACN,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,+BAA+B,EAC/B,8BAA8B,EAC9B,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,6BAA6B,EAC7B,KAAK,6BAA6B,EAClC,KAAK,gCAAgC,EACrC,sCAAsC,EACtC,yBAAyB,GACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACN,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExF,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,UAAU,EACV,yBAAyB,EACzB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,uBAAuB,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,2BAA2B,EAC3B,kCAAkC,EAClC,KAAK,iBAAiB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,EACnB,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,qBAAqB,EACrB,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,EACtB,wBAAwB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,eAAe,EACf,8BAA8B,EAC9B,2BAA2B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,uBAAuB,EACvB,KAAK,sBAAsB,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["/**\n * Core modules shared between all run modes.\n */\n\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n\ttype SessionTranscriptRepair,\n} from \"./agent-session.ts\";\nexport {\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\ttype CreateAgentSessionRuntimeResult,\n\tcreateAgentSessionRuntime,\n} from \"./agent-session-runtime.ts\";\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\nexport { type BashExecutorOptions, type BashResult, executeBashWithOperations } from \"./bash-executor.ts\";\nexport {\n\ttype CompactionBarrierResult,\n\ttype CompactionCommitDecision,\n\ttype CompactionEnvelope,\n\ttype CompactionHysteresisConfig,\n\ttype CompactionHysteresisState,\n\ttype CompactionResult,\n\ttype CompactionTransaction,\n\tcreateCompactionEnvelope,\n\tcreateCompactionHysteresisConfig,\n\tcreateCompactionHysteresisState,\n\tcreateCompactionSourceIdentity,\n\tcreateCompactionTransaction,\n\tcreateSessionRevisionToken,\n\tdecideCompactionCommit,\n\tevaluateCompactionBarrier,\n\tstepCompactionHysteresis,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/index.ts\";\nexport {\n\tapplyContextCacheInvalidation,\n\ttype ContextCacheInvalidationEvent,\n\ttype ContextCacheInvalidationSnapshot,\n\tcreateContextCacheInvalidationSnapshot,\n\tplanPromptContextBudgetV2,\n} from \"./context-budget-governor-v2.ts\";\nexport {\n\tcomputeReservedTokenBudget,\n\testimateToolResultReserve,\n\tReservedTokenBudgetError,\n} from \"./context-budget-reserved-tokens.ts\";\nexport { createEventBus, type EventBus, type EventBusController } from \"./event-bus.ts\";\n// Extensions system\nexport {\n\ttype AgentEndEvent,\n\ttype AgentStartEvent,\n\ttype AgentToolResult,\n\ttype AgentToolUpdateCallback,\n\ttype BeforeAgentStartEvent,\n\ttype BeforeAgentStartEventResult,\n\ttype BuildSystemPromptOptions,\n\ttype ContextEvent,\n\tdefineTool,\n\tdiscoverAndLoadExtensions,\n\ttype ExecOptions,\n\ttype ExecResult,\n\ttype Extension,\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n\ttype ExtensionError,\n\ttype ExtensionEvent,\n\ttype ExtensionFactory,\n\ttype ExtensionFlag,\n\ttype ExtensionHandler,\n\tExtensionRunner,\n\ttype ExtensionShortcut,\n\ttype ExtensionUIContext,\n\ttype LoadExtensionsResult,\n\ttype MessageRenderer,\n\ttype RegisteredCommand,\n\ttype SessionBeforeCompactEvent,\n\ttype SessionBeforeForkEvent,\n\ttype SessionBeforeSwitchEvent,\n\ttype SessionBeforeTreeEvent,\n\ttype SessionCompactEvent,\n\ttype SessionShutdownEvent,\n\ttype SessionStartEvent,\n\ttype SessionTreeEvent,\n\ttype ToolCallEvent,\n\ttype ToolCallEventResult,\n\ttype ToolDefinition,\n\ttype ToolRenderResultOptions,\n\ttype ToolResultEvent,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\ttype WorkingIndicatorOptions,\n} from \"./extensions/index.ts\";\nexport {\n\tDEFAULT_PROVIDER_RESILIENCE,\n\tDEFAULT_SAFETY_FAILOVER_CANDIDATES,\n\ttype FailoverCandidate,\n\tisContentSafetyStopMessage,\n\tisOrphanToolCallIdError,\n\tisStickySafetyModel,\n\tisTransientProviderErrorMessage,\n\ttype ProviderResilienceSettings,\n\tpickFailoverCandidate,\n\tresolveFailoverCandidates,\n\tresolveProviderResilience,\n\tSTICKY_SAFETY_MODEL_RE,\n\tstickySafetyBlockMessage,\n} from \"./provider-resilience.ts\";\nexport {\n\tappendRunJournalRecordDurably,\n\ttype OpenRunJournalStoreOptions,\n\ttype RunJournalQuarantineReport,\n\tRunJournalStore,\n\tRunJournalStoreCorruptionError,\n\twriteQuarantineBytesDurably,\n} from \"./run-journal-store.ts\";\nexport {\n\tclassifySessionTermination,\n\tformatSessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n\tSessionTerminationError,\n\ttype SessionTerminationKind,\n} from \"./session-termination.ts\";\nexport { createSyntheticSourceInfo } from \"./source-info.ts\";\n"]}
@@ -11,6 +11,7 @@ export { computeReservedTokenBudget, estimateToolResultReserve, ReservedTokenBud
11
11
  export { createEventBus } from "./event-bus.js";
12
12
  // Extensions system
13
13
  export { defineTool, discoverAndLoadExtensions, ExtensionRunner, } from "./extensions/index.js";
14
+ export { DEFAULT_PROVIDER_RESILIENCE, DEFAULT_SAFETY_FAILOVER_CANDIDATES, isContentSafetyStopMessage, isOrphanToolCallIdError, isStickySafetyModel, isTransientProviderErrorMessage, pickFailoverCandidate, resolveFailoverCandidates, resolveProviderResilience, STICKY_SAFETY_MODEL_RE, stickySafetyBlockMessage, } from "./provider-resilience.js";
14
15
  export { appendRunJournalRecordDurably, RunJournalStore, RunJournalStoreCorruptionError, writeQuarantineBytesDurably, } from "./run-journal-store.js";
15
16
  export { classifySessionTermination, formatSessionTermination, SessionTerminationError, } from "./session-termination.js";
16
17
  export { createSyntheticSourceInfo } from "./source-info.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,YAAY,GAQZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,mBAAmB,EAGnB,yBAAyB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAKN,8BAA8B,EAC9B,0BAA0B,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAA6C,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC1G,OAAO,EAQN,wBAAwB,EACxB,gCAAgC,EAChC,+BAA+B,EAC/B,8BAA8B,EAC9B,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,6BAA6B,EAG7B,sCAAsC,EACtC,yBAAyB,GACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACN,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,cAAc,EAA0C,MAAM,gBAAgB,CAAC;AACxF,oBAAoB;AACpB,OAAO,EASN,UAAU,EACV,yBAAyB,EAYzB,eAAe,GAsBf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,6BAA6B,EAG7B,eAAe,EACf,8BAA8B,EAC9B,2BAA2B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,wBAAwB,EAGxB,uBAAuB,GAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["/**\n * Core modules shared between all run modes.\n */\n\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n\ttype SessionTranscriptRepair,\n} from \"./agent-session.ts\";\nexport {\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\ttype CreateAgentSessionRuntimeResult,\n\tcreateAgentSessionRuntime,\n} from \"./agent-session-runtime.ts\";\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\nexport { type BashExecutorOptions, type BashResult, executeBashWithOperations } from \"./bash-executor.ts\";\nexport {\n\ttype CompactionBarrierResult,\n\ttype CompactionCommitDecision,\n\ttype CompactionEnvelope,\n\ttype CompactionHysteresisConfig,\n\ttype CompactionHysteresisState,\n\ttype CompactionResult,\n\ttype CompactionTransaction,\n\tcreateCompactionEnvelope,\n\tcreateCompactionHysteresisConfig,\n\tcreateCompactionHysteresisState,\n\tcreateCompactionSourceIdentity,\n\tcreateCompactionTransaction,\n\tcreateSessionRevisionToken,\n\tdecideCompactionCommit,\n\tevaluateCompactionBarrier,\n\tstepCompactionHysteresis,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/index.ts\";\nexport {\n\tapplyContextCacheInvalidation,\n\ttype ContextCacheInvalidationEvent,\n\ttype ContextCacheInvalidationSnapshot,\n\tcreateContextCacheInvalidationSnapshot,\n\tplanPromptContextBudgetV2,\n} from \"./context-budget-governor-v2.ts\";\nexport {\n\tcomputeReservedTokenBudget,\n\testimateToolResultReserve,\n\tReservedTokenBudgetError,\n} from \"./context-budget-reserved-tokens.ts\";\nexport { createEventBus, type EventBus, type EventBusController } from \"./event-bus.ts\";\n// Extensions system\nexport {\n\ttype AgentEndEvent,\n\ttype AgentStartEvent,\n\ttype AgentToolResult,\n\ttype AgentToolUpdateCallback,\n\ttype BeforeAgentStartEvent,\n\ttype BeforeAgentStartEventResult,\n\ttype BuildSystemPromptOptions,\n\ttype ContextEvent,\n\tdefineTool,\n\tdiscoverAndLoadExtensions,\n\ttype ExecOptions,\n\ttype ExecResult,\n\ttype Extension,\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n\ttype ExtensionError,\n\ttype ExtensionEvent,\n\ttype ExtensionFactory,\n\ttype ExtensionFlag,\n\ttype ExtensionHandler,\n\tExtensionRunner,\n\ttype ExtensionShortcut,\n\ttype ExtensionUIContext,\n\ttype LoadExtensionsResult,\n\ttype MessageRenderer,\n\ttype RegisteredCommand,\n\ttype SessionBeforeCompactEvent,\n\ttype SessionBeforeForkEvent,\n\ttype SessionBeforeSwitchEvent,\n\ttype SessionBeforeTreeEvent,\n\ttype SessionCompactEvent,\n\ttype SessionShutdownEvent,\n\ttype SessionStartEvent,\n\ttype SessionTreeEvent,\n\ttype ToolCallEvent,\n\ttype ToolCallEventResult,\n\ttype ToolDefinition,\n\ttype ToolRenderResultOptions,\n\ttype ToolResultEvent,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\ttype WorkingIndicatorOptions,\n} from \"./extensions/index.ts\";\nexport {\n\tappendRunJournalRecordDurably,\n\ttype OpenRunJournalStoreOptions,\n\ttype RunJournalQuarantineReport,\n\tRunJournalStore,\n\tRunJournalStoreCorruptionError,\n\twriteQuarantineBytesDurably,\n} from \"./run-journal-store.ts\";\nexport {\n\tclassifySessionTermination,\n\tformatSessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n\tSessionTerminationError,\n\ttype SessionTerminationKind,\n} from \"./session-termination.ts\";\nexport { createSyntheticSourceInfo } from \"./source-info.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,YAAY,GAQZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,mBAAmB,EAGnB,yBAAyB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAKN,8BAA8B,EAC9B,0BAA0B,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAA6C,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC1G,OAAO,EAQN,wBAAwB,EACxB,gCAAgC,EAChC,+BAA+B,EAC/B,8BAA8B,EAC9B,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,6BAA6B,EAG7B,sCAAsC,EACtC,yBAAyB,GACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACN,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,cAAc,EAA0C,MAAM,gBAAgB,CAAC;AACxF,oBAAoB;AACpB,OAAO,EASN,UAAU,EACV,yBAAyB,EAYzB,eAAe,GAsBf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,2BAA2B,EAC3B,kCAAkC,EAElC,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,EACnB,+BAA+B,EAE/B,qBAAqB,EACrB,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,EACtB,wBAAwB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,6BAA6B,EAG7B,eAAe,EACf,8BAA8B,EAC9B,2BAA2B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,wBAAwB,EAGxB,uBAAuB,GAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["/**\n * Core modules shared between all run modes.\n */\n\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n\ttype SessionTranscriptRepair,\n} from \"./agent-session.ts\";\nexport {\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\ttype CreateAgentSessionRuntimeResult,\n\tcreateAgentSessionRuntime,\n} from \"./agent-session-runtime.ts\";\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\nexport { type BashExecutorOptions, type BashResult, executeBashWithOperations } from \"./bash-executor.ts\";\nexport {\n\ttype CompactionBarrierResult,\n\ttype CompactionCommitDecision,\n\ttype CompactionEnvelope,\n\ttype CompactionHysteresisConfig,\n\ttype CompactionHysteresisState,\n\ttype CompactionResult,\n\ttype CompactionTransaction,\n\tcreateCompactionEnvelope,\n\tcreateCompactionHysteresisConfig,\n\tcreateCompactionHysteresisState,\n\tcreateCompactionSourceIdentity,\n\tcreateCompactionTransaction,\n\tcreateSessionRevisionToken,\n\tdecideCompactionCommit,\n\tevaluateCompactionBarrier,\n\tstepCompactionHysteresis,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/index.ts\";\nexport {\n\tapplyContextCacheInvalidation,\n\ttype ContextCacheInvalidationEvent,\n\ttype ContextCacheInvalidationSnapshot,\n\tcreateContextCacheInvalidationSnapshot,\n\tplanPromptContextBudgetV2,\n} from \"./context-budget-governor-v2.ts\";\nexport {\n\tcomputeReservedTokenBudget,\n\testimateToolResultReserve,\n\tReservedTokenBudgetError,\n} from \"./context-budget-reserved-tokens.ts\";\nexport { createEventBus, type EventBus, type EventBusController } from \"./event-bus.ts\";\n// Extensions system\nexport {\n\ttype AgentEndEvent,\n\ttype AgentStartEvent,\n\ttype AgentToolResult,\n\ttype AgentToolUpdateCallback,\n\ttype BeforeAgentStartEvent,\n\ttype BeforeAgentStartEventResult,\n\ttype BuildSystemPromptOptions,\n\ttype ContextEvent,\n\tdefineTool,\n\tdiscoverAndLoadExtensions,\n\ttype ExecOptions,\n\ttype ExecResult,\n\ttype Extension,\n\ttype ExtensionAPI,\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n\ttype ExtensionError,\n\ttype ExtensionEvent,\n\ttype ExtensionFactory,\n\ttype ExtensionFlag,\n\ttype ExtensionHandler,\n\tExtensionRunner,\n\ttype ExtensionShortcut,\n\ttype ExtensionUIContext,\n\ttype LoadExtensionsResult,\n\ttype MessageRenderer,\n\ttype RegisteredCommand,\n\ttype SessionBeforeCompactEvent,\n\ttype SessionBeforeForkEvent,\n\ttype SessionBeforeSwitchEvent,\n\ttype SessionBeforeTreeEvent,\n\ttype SessionCompactEvent,\n\ttype SessionShutdownEvent,\n\ttype SessionStartEvent,\n\ttype SessionTreeEvent,\n\ttype ToolCallEvent,\n\ttype ToolCallEventResult,\n\ttype ToolDefinition,\n\ttype ToolRenderResultOptions,\n\ttype ToolResultEvent,\n\ttype TurnEndEvent,\n\ttype TurnStartEvent,\n\ttype WorkingIndicatorOptions,\n} from \"./extensions/index.ts\";\nexport {\n\tDEFAULT_PROVIDER_RESILIENCE,\n\tDEFAULT_SAFETY_FAILOVER_CANDIDATES,\n\ttype FailoverCandidate,\n\tisContentSafetyStopMessage,\n\tisOrphanToolCallIdError,\n\tisStickySafetyModel,\n\tisTransientProviderErrorMessage,\n\ttype ProviderResilienceSettings,\n\tpickFailoverCandidate,\n\tresolveFailoverCandidates,\n\tresolveProviderResilience,\n\tSTICKY_SAFETY_MODEL_RE,\n\tstickySafetyBlockMessage,\n} from \"./provider-resilience.ts\";\nexport {\n\tappendRunJournalRecordDurably,\n\ttype OpenRunJournalStoreOptions,\n\ttype RunJournalQuarantineReport,\n\tRunJournalStore,\n\tRunJournalStoreCorruptionError,\n\twriteQuarantineBytesDurably,\n} from \"./run-journal-store.ts\";\nexport {\n\tclassifySessionTermination,\n\tformatSessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n\tSessionTerminationError,\n\ttype SessionTerminationKind,\n} from \"./session-termination.ts\";\nexport { createSyntheticSourceInfo } from \"./source-info.ts\";\n"]}
@@ -4,6 +4,14 @@ type MetricsSamplerOptions = {
4
4
  readMemory?: () => {
5
5
  rss: number;
6
6
  };
7
+ readSystemCpuTimes?: () => {
8
+ idle: number;
9
+ total: number;
10
+ };
11
+ readSystemMemory?: () => {
12
+ total: number;
13
+ free: number;
14
+ };
7
15
  cpuCount?: number;
8
16
  emaAlpha?: number;
9
17
  historySize?: number;
@@ -24,6 +32,8 @@ export declare class MetricsSampler {
24
32
  private readonly now;
25
33
  private readonly readCpu;
26
34
  private readonly readMemory;
35
+ private readonly readSystemCpuTimes;
36
+ private readonly readSystemMemory;
27
37
  private timer;
28
38
  private prevCpu;
29
39
  private prevTime;
@@ -38,6 +48,10 @@ export declare class MetricsSampler {
38
48
  private readonly spikeThreshold;
39
49
  private cpuSpikeCount;
40
50
  private wasCpuSpike;
51
+ private prevSysCpu;
52
+ private systemCpuPercent;
53
+ private systemMemoryUsedBytes;
54
+ private systemMemoryTotalBytes;
41
55
  /**
42
56
  * Create a sampler. All dependencies can be injected for deterministic
43
57
  * testing; omitted options default to real process/OS sources.
@@ -54,6 +68,12 @@ export declare class MetricsSampler {
54
68
  getCpuPercent(): number | null;
55
69
  /** The most recently sampled RSS memory size in bytes, or `null` before the first sample. */
56
70
  getMemoryRssBytes(): number | null;
71
+ /** System-wide CPU busy percent (0-100) across all cores, or `null` before the first sample. */
72
+ getSystemCpuPercent(): number | null;
73
+ /** System-wide used memory in bytes (total - free), or `null` before the first sample. */
74
+ getSystemMemoryUsedBytes(): number | null;
75
+ /** System total physical memory in bytes, or `null` before the first sample. */
76
+ getSystemMemoryTotalBytes(): number | null;
57
77
  /** The highest smoothed CPU percent observed since start, or `null` before the first sample. */
58
78
  getCpuPeak(): number | null;
59
79
  getCpuSpikeCount(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-sampler.d.ts","sourceRoot":"","sources":["../../src/core/metrics-sampler.ts"],"names":[],"mappings":"AAWA,KAAK,qBAAqB,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC;IACtD,UAAU,CAAC,EAAE,MAAM;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IAEnD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAS;IAE5B;;;OAGG;IACH,YAAY,OAAO,CAAC,EAAE,qBAAqB,EAwB1C;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,SAAO,GAAG,IAAI,CAa7B;IAED,2DAA2D;IAC3D,IAAI,IAAI,IAAI,CAaX;IAED,sGAAsG;IACtG,aAAa,IAAI,MAAM,GAAG,IAAI,CAE7B;IAED,6FAA6F;IAC7F,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjC;IAED,gGAAgG;IAChG,UAAU,IAAI,MAAM,GAAG,IAAI,CAE1B;IAED,gBAAgB,IAAI,MAAM,CAEzB;IAED;;;OAGG;IACH,gBAAgB,CAAC,MAAM,SAAyB,GAAG,MAAM,GAAG,IAAI,CAc/D;IAED,OAAO,CAAC,MAAM;CA+Cd","sourcesContent":["import * as os from \"node:os\";\n\nconst DEFAULT_EMA_ALPHA = 0.3;\nconst DEFAULT_CPU_HISTORY_SIZE = 120;\nconst DEFAULT_ROLLING_WINDOW_SIZE = 5;\nconst DEFAULT_SPIKE_THRESHOLD = 80;\nconst MIN_CPU_HISTORY_SIZE = 1;\nconst MAX_CPU_HISTORY_SIZE = 120;\nconst MIN_SPIKE_THRESHOLD = 0;\nconst MAX_SPIKE_THRESHOLD = 100;\n\ntype MetricsSamplerOptions = {\n\tnow?: () => number;\n\treadCpu?: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\treadMemory?: () => { rss: number };\n\tcpuCount?: number;\n\temaAlpha?: number;\n\thistorySize?: number;\n\trollingWindowSize?: number;\n\tspikeThreshold?: number;\n};\n\n/**\n * Samples process CPU and memory usage on a fixed interval.\n *\n * CPU% is computed from `process.cpuUsage(prev)` deltas normalized by elapsed\n * wall-clock time and the number of logical CPUs. The raw delta percent is\n * then smoothed with an exponential moving average (EMA). Memory is read from\n * `process.memoryUsage().rss`.\n *\n * The interval timer is `unref()`-ed so it never keeps the process alive.\n */\nexport class MetricsSampler {\n\tprivate readonly now: () => number;\n\tprivate readonly readCpu: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\tprivate readonly readMemory: () => { rss: number };\n\n\tprivate timer: ReturnType<typeof setInterval> | null = null;\n\tprivate prevCpu: NodeJS.CpuUsage | null = null;\n\tprivate prevTime: number | null = null;\n\tprivate cpuPercent: number | null = null;\n\tprivate memoryRssBytes: number | null = null;\n\tprivate cpuCount: number;\n\tprivate cpuPeak: number | null = null;\n\tprivate readonly smoothedHistory: number[] = [];\n\tprivate readonly emaAlpha: number;\n\tprivate readonly historySize: number;\n\tprivate readonly rollingWindowSize: number;\n\tprivate readonly spikeThreshold: number;\n\tprivate cpuSpikeCount = 0;\n\tprivate wasCpuSpike = false;\n\n\t/**\n\t * Create a sampler. All dependencies can be injected for deterministic\n\t * testing; omitted options default to real process/OS sources.\n\t */\n\tconstructor(options?: MetricsSamplerOptions) {\n\t\tthis.now = options?.now ?? (() => Date.now());\n\t\tthis.readCpu = options?.readCpu ?? ((prev?: NodeJS.CpuUsage) => process.cpuUsage(prev));\n\t\tthis.readMemory = options?.readMemory ?? (() => process.memoryUsage());\n\t\tthis.cpuCount = sanitizeInteger(options?.cpuCount, os.cpus().length, 1, Number.MAX_SAFE_INTEGER);\n\t\tthis.emaAlpha = sanitizeNumber(options?.emaAlpha, DEFAULT_EMA_ALPHA, 0, 1);\n\t\tthis.historySize = sanitizeInteger(\n\t\t\toptions?.historySize,\n\t\t\tDEFAULT_CPU_HISTORY_SIZE,\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tMAX_CPU_HISTORY_SIZE,\n\t\t);\n\t\tthis.rollingWindowSize = sanitizeInteger(\n\t\t\toptions?.rollingWindowSize,\n\t\t\tMath.min(DEFAULT_ROLLING_WINDOW_SIZE, this.historySize),\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tthis.historySize,\n\t\t);\n\t\tthis.spikeThreshold = sanitizeNumber(\n\t\t\toptions?.spikeThreshold,\n\t\t\tDEFAULT_SPIKE_THRESHOLD,\n\t\t\tMIN_SPIKE_THRESHOLD,\n\t\t\tMAX_SPIKE_THRESHOLD,\n\t\t);\n\t}\n\n\t/**\n\t * Start sampling. If already running, the existing timer is stopped and\n\t * restarted with the new interval.\n\t */\n\tstart(intervalMs = 2000): void {\n\t\tthis.stop();\n\t\tthis.prevCpu = this.readCpu();\n\t\tthis.prevTime = this.now();\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\n\t\tthis.timer = setInterval(() => this.sample(), intervalMs);\n\t\tthis.timer.unref();\n\t}\n\n\t/** Stop sampling and reset all cached values to `null`. */\n\tstop(): void {\n\t\tif (this.timer) {\n\t\t\tclearInterval(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tthis.prevCpu = null;\n\t\tthis.prevTime = null;\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\t}\n\n\t/** The most recently sampled, EMA-smoothed CPU percent (0-100), or `null` before the first sample. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.cpuPercent;\n\t}\n\n\t/** The most recently sampled RSS memory size in bytes, or `null` before the first sample. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.memoryRssBytes;\n\t}\n\n\t/** The highest smoothed CPU percent observed since start, or `null` before the first sample. */\n\tgetCpuPeak(): number | null {\n\t\treturn this.cpuPeak;\n\t}\n\n\tgetCpuSpikeCount(): number {\n\t\treturn this.cpuSpikeCount;\n\t}\n\n\t/**\n\t * The mean of the last `window` smoothed CPU percent samples, or `null` if\n\t * fewer than `window` samples have been collected.\n\t */\n\tgetCpuRollingAvg(window = this.rollingWindowSize): number | null {\n\t\tif (!Number.isFinite(window) || window <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst sampleWindow = Math.floor(window);\n\t\tif (this.smoothedHistory.length < sampleWindow) {\n\t\t\treturn null;\n\t\t}\n\t\tconst start = this.smoothedHistory.length - sampleWindow;\n\t\tlet sum = 0;\n\t\tfor (let i = start; i < this.smoothedHistory.length; i++) {\n\t\t\tsum += this.smoothedHistory[i];\n\t\t}\n\t\treturn sum / sampleWindow;\n\t}\n\n\tprivate sample(): void {\n\t\tif (!this.prevCpu || this.prevTime === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = this.now();\n\t\tconst elapsedMs = now - this.prevTime;\n\t\tif (elapsedMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst delta = this.readCpu(this.prevCpu);\n\t\tconst deltaMicroseconds = delta.user + delta.system;\n\n\t\t// Convert microseconds of CPU time into a percentage of total CPU capacity.\n\t\t// One core-second per elapsed wall second is 100% of one core; dividing by\n\t\t// cpuCount gives the percentage of total system CPU capacity.\n\t\tconst coreFraction = deltaMicroseconds / (elapsedMs * 1000);\n\t\tconst rawPercent = (coreFraction / this.cpuCount) * 100;\n\t\tconst clampedRaw = clamp(rawPercent, 0, 100);\n\n\t\t// First sample seeds the EMA; subsequent samples blend with prior value.\n\t\tconst smoothed =\n\t\t\tthis.cpuPercent === null ? clampedRaw : this.emaAlpha * clampedRaw + (1 - this.emaAlpha) * this.cpuPercent;\n\n\t\tthis.cpuPercent = smoothed;\n\t\tthis.memoryRssBytes = this.readMemory().rss;\n\t\tthis.smoothedHistory.push(smoothed);\n\t\tif (this.smoothedHistory.length > this.historySize) {\n\t\t\tthis.smoothedHistory.shift();\n\t\t}\n\t\tif (this.cpuPeak === null || smoothed > this.cpuPeak) {\n\t\t\tthis.cpuPeak = smoothed;\n\t\t}\n\t\tconst isCpuSpike = smoothed > this.spikeThreshold;\n\t\tif (isCpuSpike && !this.wasCpuSpike) {\n\t\t\tthis.cpuSpikeCount++;\n\t\t}\n\t\tthis.wasCpuSpike = isCpuSpike;\n\n\t\t// Accumulate the delta so the next sample computes from the same baseline.\n\t\tthis.prevCpu = {\n\t\t\tuser: this.prevCpu.user + delta.user,\n\t\t\tsystem: this.prevCpu.system + delta.system,\n\t\t};\n\t\tthis.prevTime = now;\n\t}\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction sanitizeNumber(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn clamp(value, min, max);\n}\n\nfunction sanitizeInteger(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(clamp(value, min, max));\n}\n"]}
1
+ {"version":3,"file":"metrics-sampler.d.ts","sourceRoot":"","sources":["../../src/core/metrics-sampler.ts"],"names":[],"mappings":"AAWA,KAAK,qBAAqB,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC;IACtD,UAAU,CAAC,EAAE,MAAM;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,gBAAgB,CAAC,EAAE,MAAM;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwC;IAC3E,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IAEzE,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAgD;IAClE,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,sBAAsB,CAAuB;IAErD;;;OAGG;IACH,YAAY,OAAO,CAAC,EAAE,qBAAqB,EA0B1C;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,SAAO,GAAG,IAAI,CAiB7B;IAED,2DAA2D;IAC3D,IAAI,IAAI,IAAI,CAiBX;IAED,sGAAsG;IACtG,aAAa,IAAI,MAAM,GAAG,IAAI,CAE7B;IAED,6FAA6F;IAC7F,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjC;IAED,gGAAgG;IAChG,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAEnC;IAED,0FAA0F;IAC1F,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAExC;IAED,gFAAgF;IAChF,yBAAyB,IAAI,MAAM,GAAG,IAAI,CAEzC;IAED,gGAAgG;IAChG,UAAU,IAAI,MAAM,GAAG,IAAI,CAE1B;IAED,gBAAgB,IAAI,MAAM,CAEzB;IAED;;;OAGG;IACH,gBAAgB,CAAC,MAAM,SAAyB,GAAG,MAAM,GAAG,IAAI,CAc/D;IAED,OAAO,CAAC,MAAM;CA+Dd","sourcesContent":["import * as os from \"node:os\";\n\nconst DEFAULT_EMA_ALPHA = 0.3;\nconst DEFAULT_CPU_HISTORY_SIZE = 120;\nconst DEFAULT_ROLLING_WINDOW_SIZE = 5;\nconst DEFAULT_SPIKE_THRESHOLD = 80;\nconst MIN_CPU_HISTORY_SIZE = 1;\nconst MAX_CPU_HISTORY_SIZE = 120;\nconst MIN_SPIKE_THRESHOLD = 0;\nconst MAX_SPIKE_THRESHOLD = 100;\n\ntype MetricsSamplerOptions = {\n\tnow?: () => number;\n\treadCpu?: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\treadMemory?: () => { rss: number };\n\treadSystemCpuTimes?: () => { idle: number; total: number };\n\treadSystemMemory?: () => { total: number; free: number };\n\tcpuCount?: number;\n\temaAlpha?: number;\n\thistorySize?: number;\n\trollingWindowSize?: number;\n\tspikeThreshold?: number;\n};\n\n/**\n * Samples process CPU and memory usage on a fixed interval.\n *\n * CPU% is computed from `process.cpuUsage(prev)` deltas normalized by elapsed\n * wall-clock time and the number of logical CPUs. The raw delta percent is\n * then smoothed with an exponential moving average (EMA). Memory is read from\n * `process.memoryUsage().rss`.\n *\n * The interval timer is `unref()`-ed so it never keeps the process alive.\n */\nexport class MetricsSampler {\n\tprivate readonly now: () => number;\n\tprivate readonly readCpu: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\tprivate readonly readMemory: () => { rss: number };\n\tprivate readonly readSystemCpuTimes: () => { idle: number; total: number };\n\tprivate readonly readSystemMemory: () => { total: number; free: number };\n\n\tprivate timer: ReturnType<typeof setInterval> | null = null;\n\tprivate prevCpu: NodeJS.CpuUsage | null = null;\n\tprivate prevTime: number | null = null;\n\tprivate cpuPercent: number | null = null;\n\tprivate memoryRssBytes: number | null = null;\n\tprivate cpuCount: number;\n\tprivate cpuPeak: number | null = null;\n\tprivate readonly smoothedHistory: number[] = [];\n\tprivate readonly emaAlpha: number;\n\tprivate readonly historySize: number;\n\tprivate readonly rollingWindowSize: number;\n\tprivate readonly spikeThreshold: number;\n\tprivate cpuSpikeCount = 0;\n\tprivate wasCpuSpike = false;\n\tprivate prevSysCpu: { idle: number; total: number } | null = null;\n\tprivate systemCpuPercent: number | null = null;\n\tprivate systemMemoryUsedBytes: number | null = null;\n\tprivate systemMemoryTotalBytes: number | null = null;\n\n\t/**\n\t * Create a sampler. All dependencies can be injected for deterministic\n\t * testing; omitted options default to real process/OS sources.\n\t */\n\tconstructor(options?: MetricsSamplerOptions) {\n\t\tthis.now = options?.now ?? (() => Date.now());\n\t\tthis.readCpu = options?.readCpu ?? ((prev?: NodeJS.CpuUsage) => process.cpuUsage(prev));\n\t\tthis.readMemory = options?.readMemory ?? (() => process.memoryUsage());\n\t\tthis.cpuCount = sanitizeInteger(options?.cpuCount, os.cpus().length, 1, Number.MAX_SAFE_INTEGER);\n\t\tthis.emaAlpha = sanitizeNumber(options?.emaAlpha, DEFAULT_EMA_ALPHA, 0, 1);\n\t\tthis.historySize = sanitizeInteger(\n\t\t\toptions?.historySize,\n\t\t\tDEFAULT_CPU_HISTORY_SIZE,\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tMAX_CPU_HISTORY_SIZE,\n\t\t);\n\t\tthis.rollingWindowSize = sanitizeInteger(\n\t\t\toptions?.rollingWindowSize,\n\t\t\tMath.min(DEFAULT_ROLLING_WINDOW_SIZE, this.historySize),\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tthis.historySize,\n\t\t);\n\t\tthis.spikeThreshold = sanitizeNumber(\n\t\t\toptions?.spikeThreshold,\n\t\t\tDEFAULT_SPIKE_THRESHOLD,\n\t\t\tMIN_SPIKE_THRESHOLD,\n\t\t\tMAX_SPIKE_THRESHOLD,\n\t\t);\n\t\tthis.readSystemCpuTimes = options?.readSystemCpuTimes ?? (() => readOsCpuTimes());\n\t\tthis.readSystemMemory = options?.readSystemMemory ?? (() => ({ total: os.totalmem(), free: os.freemem() }));\n\t}\n\n\t/**\n\t * Start sampling. If already running, the existing timer is stopped and\n\t * restarted with the new interval.\n\t */\n\tstart(intervalMs = 2000): void {\n\t\tthis.stop();\n\t\tthis.prevCpu = this.readCpu();\n\t\tthis.prevTime = this.now();\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.prevSysCpu = this.readSystemCpuTimes();\n\t\tthis.systemCpuPercent = null;\n\t\tthis.systemMemoryUsedBytes = null;\n\t\tthis.systemMemoryTotalBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\n\t\tthis.timer = setInterval(() => this.sample(), intervalMs);\n\t\tthis.timer.unref();\n\t}\n\n\t/** Stop sampling and reset all cached values to `null`. */\n\tstop(): void {\n\t\tif (this.timer) {\n\t\t\tclearInterval(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tthis.prevCpu = null;\n\t\tthis.prevTime = null;\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.prevSysCpu = null;\n\t\tthis.systemCpuPercent = null;\n\t\tthis.systemMemoryUsedBytes = null;\n\t\tthis.systemMemoryTotalBytes = null;\n\t\tthis.smoothedHistory.length = 0;\n\t}\n\n\t/** The most recently sampled, EMA-smoothed CPU percent (0-100), or `null` before the first sample. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.cpuPercent;\n\t}\n\n\t/** The most recently sampled RSS memory size in bytes, or `null` before the first sample. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.memoryRssBytes;\n\t}\n\n\t/** System-wide CPU busy percent (0-100) across all cores, or `null` before the first sample. */\n\tgetSystemCpuPercent(): number | null {\n\t\treturn this.systemCpuPercent;\n\t}\n\n\t/** System-wide used memory in bytes (total - free), or `null` before the first sample. */\n\tgetSystemMemoryUsedBytes(): number | null {\n\t\treturn this.systemMemoryUsedBytes;\n\t}\n\n\t/** System total physical memory in bytes, or `null` before the first sample. */\n\tgetSystemMemoryTotalBytes(): number | null {\n\t\treturn this.systemMemoryTotalBytes;\n\t}\n\n\t/** The highest smoothed CPU percent observed since start, or `null` before the first sample. */\n\tgetCpuPeak(): number | null {\n\t\treturn this.cpuPeak;\n\t}\n\n\tgetCpuSpikeCount(): number {\n\t\treturn this.cpuSpikeCount;\n\t}\n\n\t/**\n\t * The mean of the last `window` smoothed CPU percent samples, or `null` if\n\t * fewer than `window` samples have been collected.\n\t */\n\tgetCpuRollingAvg(window = this.rollingWindowSize): number | null {\n\t\tif (!Number.isFinite(window) || window <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst sampleWindow = Math.floor(window);\n\t\tif (this.smoothedHistory.length < sampleWindow) {\n\t\t\treturn null;\n\t\t}\n\t\tconst start = this.smoothedHistory.length - sampleWindow;\n\t\tlet sum = 0;\n\t\tfor (let i = start; i < this.smoothedHistory.length; i++) {\n\t\t\tsum += this.smoothedHistory[i];\n\t\t}\n\t\treturn sum / sampleWindow;\n\t}\n\n\tprivate sample(): void {\n\t\tif (!this.prevCpu || this.prevTime === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = this.now();\n\t\tconst elapsedMs = now - this.prevTime;\n\t\tif (elapsedMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst delta = this.readCpu(this.prevCpu);\n\t\tconst deltaMicroseconds = delta.user + delta.system;\n\n\t\t// Convert microseconds of CPU time into a percentage of total CPU capacity.\n\t\t// One core-second per elapsed wall second is 100% of one core; dividing by\n\t\t// cpuCount gives the percentage of total system CPU capacity.\n\t\tconst coreFraction = deltaMicroseconds / (elapsedMs * 1000);\n\t\tconst rawPercent = (coreFraction / this.cpuCount) * 100;\n\t\tconst clampedRaw = clamp(rawPercent, 0, 100);\n\n\t\t// First sample seeds the EMA; subsequent samples blend with prior value.\n\t\tconst smoothed =\n\t\t\tthis.cpuPercent === null ? clampedRaw : this.emaAlpha * clampedRaw + (1 - this.emaAlpha) * this.cpuPercent;\n\n\t\tthis.cpuPercent = smoothed;\n\t\tthis.memoryRssBytes = this.readMemory().rss;\n\n\t\t// System-wide sampling (whole computer): CPU busy% from os.cpus() time\n\t\t// deltas, memory from totalmem/freemem.\n\t\tif (this.prevSysCpu) {\n\t\t\tconst sys = this.readSystemCpuTimes();\n\t\t\tconst totalDelta = sys.total - this.prevSysCpu.total;\n\t\t\tconst idleDelta = sys.idle - this.prevSysCpu.idle;\n\t\t\tif (totalDelta > 0) {\n\t\t\t\tthis.systemCpuPercent = clamp(((totalDelta - idleDelta) / totalDelta) * 100, 0, 100);\n\t\t\t}\n\t\t\tthis.prevSysCpu = sys;\n\t\t}\n\t\tconst sysMem = this.readSystemMemory();\n\t\tthis.systemMemoryTotalBytes = sysMem.total;\n\t\tthis.systemMemoryUsedBytes = Math.max(0, sysMem.total - sysMem.free);\n\n\t\tthis.smoothedHistory.push(smoothed);\n\t\tif (this.smoothedHistory.length > this.historySize) {\n\t\t\tthis.smoothedHistory.shift();\n\t\t}\n\t\tif (this.cpuPeak === null || smoothed > this.cpuPeak) {\n\t\t\tthis.cpuPeak = smoothed;\n\t\t}\n\t\tconst isCpuSpike = smoothed > this.spikeThreshold;\n\t\tif (isCpuSpike && !this.wasCpuSpike) {\n\t\t\tthis.cpuSpikeCount++;\n\t\t}\n\t\tthis.wasCpuSpike = isCpuSpike;\n\n\t\t// Accumulate the delta so the next sample computes from the same baseline.\n\t\tthis.prevCpu = {\n\t\t\tuser: this.prevCpu.user + delta.user,\n\t\t\tsystem: this.prevCpu.system + delta.system,\n\t\t};\n\t\tthis.prevTime = now;\n\t}\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\n/** Aggregate os.cpus() times into { idle, total } jiffies (ms) across all cores. */\nfunction readOsCpuTimes(): { idle: number; total: number } {\n\tlet idle = 0;\n\tlet total = 0;\n\tfor (const cpu of os.cpus()) {\n\t\tidle += cpu.times.idle;\n\t\ttotal += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq;\n\t}\n\treturn { idle, total };\n}\n\nfunction sanitizeNumber(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn clamp(value, min, max);\n}\n\nfunction sanitizeInteger(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(clamp(value, min, max));\n}\n"]}
@@ -21,6 +21,8 @@ export class MetricsSampler {
21
21
  now;
22
22
  readCpu;
23
23
  readMemory;
24
+ readSystemCpuTimes;
25
+ readSystemMemory;
24
26
  timer = null;
25
27
  prevCpu = null;
26
28
  prevTime = null;
@@ -35,6 +37,10 @@ export class MetricsSampler {
35
37
  spikeThreshold;
36
38
  cpuSpikeCount = 0;
37
39
  wasCpuSpike = false;
40
+ prevSysCpu = null;
41
+ systemCpuPercent = null;
42
+ systemMemoryUsedBytes = null;
43
+ systemMemoryTotalBytes = null;
38
44
  /**
39
45
  * Create a sampler. All dependencies can be injected for deterministic
40
46
  * testing; omitted options default to real process/OS sources.
@@ -48,6 +54,8 @@ export class MetricsSampler {
48
54
  this.historySize = sanitizeInteger(options?.historySize, DEFAULT_CPU_HISTORY_SIZE, MIN_CPU_HISTORY_SIZE, MAX_CPU_HISTORY_SIZE);
49
55
  this.rollingWindowSize = sanitizeInteger(options?.rollingWindowSize, Math.min(DEFAULT_ROLLING_WINDOW_SIZE, this.historySize), MIN_CPU_HISTORY_SIZE, this.historySize);
50
56
  this.spikeThreshold = sanitizeNumber(options?.spikeThreshold, DEFAULT_SPIKE_THRESHOLD, MIN_SPIKE_THRESHOLD, MAX_SPIKE_THRESHOLD);
57
+ this.readSystemCpuTimes = options?.readSystemCpuTimes ?? (() => readOsCpuTimes());
58
+ this.readSystemMemory = options?.readSystemMemory ?? (() => ({ total: os.totalmem(), free: os.freemem() }));
51
59
  }
52
60
  /**
53
61
  * Start sampling. If already running, the existing timer is stopped and
@@ -59,6 +67,10 @@ export class MetricsSampler {
59
67
  this.prevTime = this.now();
60
68
  this.cpuPercent = null;
61
69
  this.memoryRssBytes = null;
70
+ this.prevSysCpu = this.readSystemCpuTimes();
71
+ this.systemCpuPercent = null;
72
+ this.systemMemoryUsedBytes = null;
73
+ this.systemMemoryTotalBytes = null;
62
74
  this.cpuPeak = null;
63
75
  this.cpuSpikeCount = 0;
64
76
  this.wasCpuSpike = false;
@@ -79,6 +91,10 @@ export class MetricsSampler {
79
91
  this.cpuPeak = null;
80
92
  this.cpuSpikeCount = 0;
81
93
  this.wasCpuSpike = false;
94
+ this.prevSysCpu = null;
95
+ this.systemCpuPercent = null;
96
+ this.systemMemoryUsedBytes = null;
97
+ this.systemMemoryTotalBytes = null;
82
98
  this.smoothedHistory.length = 0;
83
99
  }
84
100
  /** The most recently sampled, EMA-smoothed CPU percent (0-100), or `null` before the first sample. */
@@ -89,6 +105,18 @@ export class MetricsSampler {
89
105
  getMemoryRssBytes() {
90
106
  return this.memoryRssBytes;
91
107
  }
108
+ /** System-wide CPU busy percent (0-100) across all cores, or `null` before the first sample. */
109
+ getSystemCpuPercent() {
110
+ return this.systemCpuPercent;
111
+ }
112
+ /** System-wide used memory in bytes (total - free), or `null` before the first sample. */
113
+ getSystemMemoryUsedBytes() {
114
+ return this.systemMemoryUsedBytes;
115
+ }
116
+ /** System total physical memory in bytes, or `null` before the first sample. */
117
+ getSystemMemoryTotalBytes() {
118
+ return this.systemMemoryTotalBytes;
119
+ }
92
120
  /** The highest smoothed CPU percent observed since start, or `null` before the first sample. */
93
121
  getCpuPeak() {
94
122
  return this.cpuPeak;
@@ -136,6 +164,20 @@ export class MetricsSampler {
136
164
  const smoothed = this.cpuPercent === null ? clampedRaw : this.emaAlpha * clampedRaw + (1 - this.emaAlpha) * this.cpuPercent;
137
165
  this.cpuPercent = smoothed;
138
166
  this.memoryRssBytes = this.readMemory().rss;
167
+ // System-wide sampling (whole computer): CPU busy% from os.cpus() time
168
+ // deltas, memory from totalmem/freemem.
169
+ if (this.prevSysCpu) {
170
+ const sys = this.readSystemCpuTimes();
171
+ const totalDelta = sys.total - this.prevSysCpu.total;
172
+ const idleDelta = sys.idle - this.prevSysCpu.idle;
173
+ if (totalDelta > 0) {
174
+ this.systemCpuPercent = clamp(((totalDelta - idleDelta) / totalDelta) * 100, 0, 100);
175
+ }
176
+ this.prevSysCpu = sys;
177
+ }
178
+ const sysMem = this.readSystemMemory();
179
+ this.systemMemoryTotalBytes = sysMem.total;
180
+ this.systemMemoryUsedBytes = Math.max(0, sysMem.total - sysMem.free);
139
181
  this.smoothedHistory.push(smoothed);
140
182
  if (this.smoothedHistory.length > this.historySize) {
141
183
  this.smoothedHistory.shift();
@@ -159,6 +201,16 @@ export class MetricsSampler {
159
201
  function clamp(value, min, max) {
160
202
  return Math.max(min, Math.min(max, value));
161
203
  }
204
+ /** Aggregate os.cpus() times into { idle, total } jiffies (ms) across all cores. */
205
+ function readOsCpuTimes() {
206
+ let idle = 0;
207
+ let total = 0;
208
+ for (const cpu of os.cpus()) {
209
+ idle += cpu.times.idle;
210
+ total += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq;
211
+ }
212
+ return { idle, total };
213
+ }
162
214
  function sanitizeNumber(value, fallback, min, max) {
163
215
  if (typeof value !== "number" || !Number.isFinite(value)) {
164
216
  return fallback;
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-sampler.js","sourceRoot":"","sources":["../../src/core/metrics-sampler.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\n\nconst DEFAULT_EMA_ALPHA = 0.3;\nconst DEFAULT_CPU_HISTORY_SIZE = 120;\nconst DEFAULT_ROLLING_WINDOW_SIZE = 5;\nconst DEFAULT_SPIKE_THRESHOLD = 80;\nconst MIN_CPU_HISTORY_SIZE = 1;\nconst MAX_CPU_HISTORY_SIZE = 120;\nconst MIN_SPIKE_THRESHOLD = 0;\nconst MAX_SPIKE_THRESHOLD = 100;\n\ntype MetricsSamplerOptions = {\n\tnow?: () => number;\n\treadCpu?: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\treadMemory?: () => { rss: number };\n\tcpuCount?: number;\n\temaAlpha?: number;\n\thistorySize?: number;\n\trollingWindowSize?: number;\n\tspikeThreshold?: number;\n};\n\n/**\n * Samples process CPU and memory usage on a fixed interval.\n *\n * CPU% is computed from `process.cpuUsage(prev)` deltas normalized by elapsed\n * wall-clock time and the number of logical CPUs. The raw delta percent is\n * then smoothed with an exponential moving average (EMA). Memory is read from\n * `process.memoryUsage().rss`.\n *\n * The interval timer is `unref()`-ed so it never keeps the process alive.\n */\nexport class MetricsSampler {\n\tprivate readonly now: () => number;\n\tprivate readonly readCpu: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\tprivate readonly readMemory: () => { rss: number };\n\n\tprivate timer: ReturnType<typeof setInterval> | null = null;\n\tprivate prevCpu: NodeJS.CpuUsage | null = null;\n\tprivate prevTime: number | null = null;\n\tprivate cpuPercent: number | null = null;\n\tprivate memoryRssBytes: number | null = null;\n\tprivate cpuCount: number;\n\tprivate cpuPeak: number | null = null;\n\tprivate readonly smoothedHistory: number[] = [];\n\tprivate readonly emaAlpha: number;\n\tprivate readonly historySize: number;\n\tprivate readonly rollingWindowSize: number;\n\tprivate readonly spikeThreshold: number;\n\tprivate cpuSpikeCount = 0;\n\tprivate wasCpuSpike = false;\n\n\t/**\n\t * Create a sampler. All dependencies can be injected for deterministic\n\t * testing; omitted options default to real process/OS sources.\n\t */\n\tconstructor(options?: MetricsSamplerOptions) {\n\t\tthis.now = options?.now ?? (() => Date.now());\n\t\tthis.readCpu = options?.readCpu ?? ((prev?: NodeJS.CpuUsage) => process.cpuUsage(prev));\n\t\tthis.readMemory = options?.readMemory ?? (() => process.memoryUsage());\n\t\tthis.cpuCount = sanitizeInteger(options?.cpuCount, os.cpus().length, 1, Number.MAX_SAFE_INTEGER);\n\t\tthis.emaAlpha = sanitizeNumber(options?.emaAlpha, DEFAULT_EMA_ALPHA, 0, 1);\n\t\tthis.historySize = sanitizeInteger(\n\t\t\toptions?.historySize,\n\t\t\tDEFAULT_CPU_HISTORY_SIZE,\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tMAX_CPU_HISTORY_SIZE,\n\t\t);\n\t\tthis.rollingWindowSize = sanitizeInteger(\n\t\t\toptions?.rollingWindowSize,\n\t\t\tMath.min(DEFAULT_ROLLING_WINDOW_SIZE, this.historySize),\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tthis.historySize,\n\t\t);\n\t\tthis.spikeThreshold = sanitizeNumber(\n\t\t\toptions?.spikeThreshold,\n\t\t\tDEFAULT_SPIKE_THRESHOLD,\n\t\t\tMIN_SPIKE_THRESHOLD,\n\t\t\tMAX_SPIKE_THRESHOLD,\n\t\t);\n\t}\n\n\t/**\n\t * Start sampling. If already running, the existing timer is stopped and\n\t * restarted with the new interval.\n\t */\n\tstart(intervalMs = 2000): void {\n\t\tthis.stop();\n\t\tthis.prevCpu = this.readCpu();\n\t\tthis.prevTime = this.now();\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\n\t\tthis.timer = setInterval(() => this.sample(), intervalMs);\n\t\tthis.timer.unref();\n\t}\n\n\t/** Stop sampling and reset all cached values to `null`. */\n\tstop(): void {\n\t\tif (this.timer) {\n\t\t\tclearInterval(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tthis.prevCpu = null;\n\t\tthis.prevTime = null;\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\t}\n\n\t/** The most recently sampled, EMA-smoothed CPU percent (0-100), or `null` before the first sample. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.cpuPercent;\n\t}\n\n\t/** The most recently sampled RSS memory size in bytes, or `null` before the first sample. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.memoryRssBytes;\n\t}\n\n\t/** The highest smoothed CPU percent observed since start, or `null` before the first sample. */\n\tgetCpuPeak(): number | null {\n\t\treturn this.cpuPeak;\n\t}\n\n\tgetCpuSpikeCount(): number {\n\t\treturn this.cpuSpikeCount;\n\t}\n\n\t/**\n\t * The mean of the last `window` smoothed CPU percent samples, or `null` if\n\t * fewer than `window` samples have been collected.\n\t */\n\tgetCpuRollingAvg(window = this.rollingWindowSize): number | null {\n\t\tif (!Number.isFinite(window) || window <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst sampleWindow = Math.floor(window);\n\t\tif (this.smoothedHistory.length < sampleWindow) {\n\t\t\treturn null;\n\t\t}\n\t\tconst start = this.smoothedHistory.length - sampleWindow;\n\t\tlet sum = 0;\n\t\tfor (let i = start; i < this.smoothedHistory.length; i++) {\n\t\t\tsum += this.smoothedHistory[i];\n\t\t}\n\t\treturn sum / sampleWindow;\n\t}\n\n\tprivate sample(): void {\n\t\tif (!this.prevCpu || this.prevTime === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = this.now();\n\t\tconst elapsedMs = now - this.prevTime;\n\t\tif (elapsedMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst delta = this.readCpu(this.prevCpu);\n\t\tconst deltaMicroseconds = delta.user + delta.system;\n\n\t\t// Convert microseconds of CPU time into a percentage of total CPU capacity.\n\t\t// One core-second per elapsed wall second is 100% of one core; dividing by\n\t\t// cpuCount gives the percentage of total system CPU capacity.\n\t\tconst coreFraction = deltaMicroseconds / (elapsedMs * 1000);\n\t\tconst rawPercent = (coreFraction / this.cpuCount) * 100;\n\t\tconst clampedRaw = clamp(rawPercent, 0, 100);\n\n\t\t// First sample seeds the EMA; subsequent samples blend with prior value.\n\t\tconst smoothed =\n\t\t\tthis.cpuPercent === null ? clampedRaw : this.emaAlpha * clampedRaw + (1 - this.emaAlpha) * this.cpuPercent;\n\n\t\tthis.cpuPercent = smoothed;\n\t\tthis.memoryRssBytes = this.readMemory().rss;\n\t\tthis.smoothedHistory.push(smoothed);\n\t\tif (this.smoothedHistory.length > this.historySize) {\n\t\t\tthis.smoothedHistory.shift();\n\t\t}\n\t\tif (this.cpuPeak === null || smoothed > this.cpuPeak) {\n\t\t\tthis.cpuPeak = smoothed;\n\t\t}\n\t\tconst isCpuSpike = smoothed > this.spikeThreshold;\n\t\tif (isCpuSpike && !this.wasCpuSpike) {\n\t\t\tthis.cpuSpikeCount++;\n\t\t}\n\t\tthis.wasCpuSpike = isCpuSpike;\n\n\t\t// Accumulate the delta so the next sample computes from the same baseline.\n\t\tthis.prevCpu = {\n\t\t\tuser: this.prevCpu.user + delta.user,\n\t\t\tsystem: this.prevCpu.system + delta.system,\n\t\t};\n\t\tthis.prevTime = now;\n\t}\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction sanitizeNumber(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn clamp(value, min, max);\n}\n\nfunction sanitizeInteger(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(clamp(value, min, max));\n}\n"]}
1
+ {"version":3,"file":"metrics-sampler.js","sourceRoot":"","sources":["../../src/core/metrics-sampler.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\n\nconst DEFAULT_EMA_ALPHA = 0.3;\nconst DEFAULT_CPU_HISTORY_SIZE = 120;\nconst DEFAULT_ROLLING_WINDOW_SIZE = 5;\nconst DEFAULT_SPIKE_THRESHOLD = 80;\nconst MIN_CPU_HISTORY_SIZE = 1;\nconst MAX_CPU_HISTORY_SIZE = 120;\nconst MIN_SPIKE_THRESHOLD = 0;\nconst MAX_SPIKE_THRESHOLD = 100;\n\ntype MetricsSamplerOptions = {\n\tnow?: () => number;\n\treadCpu?: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\treadMemory?: () => { rss: number };\n\treadSystemCpuTimes?: () => { idle: number; total: number };\n\treadSystemMemory?: () => { total: number; free: number };\n\tcpuCount?: number;\n\temaAlpha?: number;\n\thistorySize?: number;\n\trollingWindowSize?: number;\n\tspikeThreshold?: number;\n};\n\n/**\n * Samples process CPU and memory usage on a fixed interval.\n *\n * CPU% is computed from `process.cpuUsage(prev)` deltas normalized by elapsed\n * wall-clock time and the number of logical CPUs. The raw delta percent is\n * then smoothed with an exponential moving average (EMA). Memory is read from\n * `process.memoryUsage().rss`.\n *\n * The interval timer is `unref()`-ed so it never keeps the process alive.\n */\nexport class MetricsSampler {\n\tprivate readonly now: () => number;\n\tprivate readonly readCpu: (prev?: NodeJS.CpuUsage) => NodeJS.CpuUsage;\n\tprivate readonly readMemory: () => { rss: number };\n\tprivate readonly readSystemCpuTimes: () => { idle: number; total: number };\n\tprivate readonly readSystemMemory: () => { total: number; free: number };\n\n\tprivate timer: ReturnType<typeof setInterval> | null = null;\n\tprivate prevCpu: NodeJS.CpuUsage | null = null;\n\tprivate prevTime: number | null = null;\n\tprivate cpuPercent: number | null = null;\n\tprivate memoryRssBytes: number | null = null;\n\tprivate cpuCount: number;\n\tprivate cpuPeak: number | null = null;\n\tprivate readonly smoothedHistory: number[] = [];\n\tprivate readonly emaAlpha: number;\n\tprivate readonly historySize: number;\n\tprivate readonly rollingWindowSize: number;\n\tprivate readonly spikeThreshold: number;\n\tprivate cpuSpikeCount = 0;\n\tprivate wasCpuSpike = false;\n\tprivate prevSysCpu: { idle: number; total: number } | null = null;\n\tprivate systemCpuPercent: number | null = null;\n\tprivate systemMemoryUsedBytes: number | null = null;\n\tprivate systemMemoryTotalBytes: number | null = null;\n\n\t/**\n\t * Create a sampler. All dependencies can be injected for deterministic\n\t * testing; omitted options default to real process/OS sources.\n\t */\n\tconstructor(options?: MetricsSamplerOptions) {\n\t\tthis.now = options?.now ?? (() => Date.now());\n\t\tthis.readCpu = options?.readCpu ?? ((prev?: NodeJS.CpuUsage) => process.cpuUsage(prev));\n\t\tthis.readMemory = options?.readMemory ?? (() => process.memoryUsage());\n\t\tthis.cpuCount = sanitizeInteger(options?.cpuCount, os.cpus().length, 1, Number.MAX_SAFE_INTEGER);\n\t\tthis.emaAlpha = sanitizeNumber(options?.emaAlpha, DEFAULT_EMA_ALPHA, 0, 1);\n\t\tthis.historySize = sanitizeInteger(\n\t\t\toptions?.historySize,\n\t\t\tDEFAULT_CPU_HISTORY_SIZE,\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tMAX_CPU_HISTORY_SIZE,\n\t\t);\n\t\tthis.rollingWindowSize = sanitizeInteger(\n\t\t\toptions?.rollingWindowSize,\n\t\t\tMath.min(DEFAULT_ROLLING_WINDOW_SIZE, this.historySize),\n\t\t\tMIN_CPU_HISTORY_SIZE,\n\t\t\tthis.historySize,\n\t\t);\n\t\tthis.spikeThreshold = sanitizeNumber(\n\t\t\toptions?.spikeThreshold,\n\t\t\tDEFAULT_SPIKE_THRESHOLD,\n\t\t\tMIN_SPIKE_THRESHOLD,\n\t\t\tMAX_SPIKE_THRESHOLD,\n\t\t);\n\t\tthis.readSystemCpuTimes = options?.readSystemCpuTimes ?? (() => readOsCpuTimes());\n\t\tthis.readSystemMemory = options?.readSystemMemory ?? (() => ({ total: os.totalmem(), free: os.freemem() }));\n\t}\n\n\t/**\n\t * Start sampling. If already running, the existing timer is stopped and\n\t * restarted with the new interval.\n\t */\n\tstart(intervalMs = 2000): void {\n\t\tthis.stop();\n\t\tthis.prevCpu = this.readCpu();\n\t\tthis.prevTime = this.now();\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.prevSysCpu = this.readSystemCpuTimes();\n\t\tthis.systemCpuPercent = null;\n\t\tthis.systemMemoryUsedBytes = null;\n\t\tthis.systemMemoryTotalBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.smoothedHistory.length = 0;\n\n\t\tthis.timer = setInterval(() => this.sample(), intervalMs);\n\t\tthis.timer.unref();\n\t}\n\n\t/** Stop sampling and reset all cached values to `null`. */\n\tstop(): void {\n\t\tif (this.timer) {\n\t\t\tclearInterval(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tthis.prevCpu = null;\n\t\tthis.prevTime = null;\n\t\tthis.cpuPercent = null;\n\t\tthis.memoryRssBytes = null;\n\t\tthis.cpuPeak = null;\n\t\tthis.cpuSpikeCount = 0;\n\t\tthis.wasCpuSpike = false;\n\t\tthis.prevSysCpu = null;\n\t\tthis.systemCpuPercent = null;\n\t\tthis.systemMemoryUsedBytes = null;\n\t\tthis.systemMemoryTotalBytes = null;\n\t\tthis.smoothedHistory.length = 0;\n\t}\n\n\t/** The most recently sampled, EMA-smoothed CPU percent (0-100), or `null` before the first sample. */\n\tgetCpuPercent(): number | null {\n\t\treturn this.cpuPercent;\n\t}\n\n\t/** The most recently sampled RSS memory size in bytes, or `null` before the first sample. */\n\tgetMemoryRssBytes(): number | null {\n\t\treturn this.memoryRssBytes;\n\t}\n\n\t/** System-wide CPU busy percent (0-100) across all cores, or `null` before the first sample. */\n\tgetSystemCpuPercent(): number | null {\n\t\treturn this.systemCpuPercent;\n\t}\n\n\t/** System-wide used memory in bytes (total - free), or `null` before the first sample. */\n\tgetSystemMemoryUsedBytes(): number | null {\n\t\treturn this.systemMemoryUsedBytes;\n\t}\n\n\t/** System total physical memory in bytes, or `null` before the first sample. */\n\tgetSystemMemoryTotalBytes(): number | null {\n\t\treturn this.systemMemoryTotalBytes;\n\t}\n\n\t/** The highest smoothed CPU percent observed since start, or `null` before the first sample. */\n\tgetCpuPeak(): number | null {\n\t\treturn this.cpuPeak;\n\t}\n\n\tgetCpuSpikeCount(): number {\n\t\treturn this.cpuSpikeCount;\n\t}\n\n\t/**\n\t * The mean of the last `window` smoothed CPU percent samples, or `null` if\n\t * fewer than `window` samples have been collected.\n\t */\n\tgetCpuRollingAvg(window = this.rollingWindowSize): number | null {\n\t\tif (!Number.isFinite(window) || window <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst sampleWindow = Math.floor(window);\n\t\tif (this.smoothedHistory.length < sampleWindow) {\n\t\t\treturn null;\n\t\t}\n\t\tconst start = this.smoothedHistory.length - sampleWindow;\n\t\tlet sum = 0;\n\t\tfor (let i = start; i < this.smoothedHistory.length; i++) {\n\t\t\tsum += this.smoothedHistory[i];\n\t\t}\n\t\treturn sum / sampleWindow;\n\t}\n\n\tprivate sample(): void {\n\t\tif (!this.prevCpu || this.prevTime === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = this.now();\n\t\tconst elapsedMs = now - this.prevTime;\n\t\tif (elapsedMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst delta = this.readCpu(this.prevCpu);\n\t\tconst deltaMicroseconds = delta.user + delta.system;\n\n\t\t// Convert microseconds of CPU time into a percentage of total CPU capacity.\n\t\t// One core-second per elapsed wall second is 100% of one core; dividing by\n\t\t// cpuCount gives the percentage of total system CPU capacity.\n\t\tconst coreFraction = deltaMicroseconds / (elapsedMs * 1000);\n\t\tconst rawPercent = (coreFraction / this.cpuCount) * 100;\n\t\tconst clampedRaw = clamp(rawPercent, 0, 100);\n\n\t\t// First sample seeds the EMA; subsequent samples blend with prior value.\n\t\tconst smoothed =\n\t\t\tthis.cpuPercent === null ? clampedRaw : this.emaAlpha * clampedRaw + (1 - this.emaAlpha) * this.cpuPercent;\n\n\t\tthis.cpuPercent = smoothed;\n\t\tthis.memoryRssBytes = this.readMemory().rss;\n\n\t\t// System-wide sampling (whole computer): CPU busy% from os.cpus() time\n\t\t// deltas, memory from totalmem/freemem.\n\t\tif (this.prevSysCpu) {\n\t\t\tconst sys = this.readSystemCpuTimes();\n\t\t\tconst totalDelta = sys.total - this.prevSysCpu.total;\n\t\t\tconst idleDelta = sys.idle - this.prevSysCpu.idle;\n\t\t\tif (totalDelta > 0) {\n\t\t\t\tthis.systemCpuPercent = clamp(((totalDelta - idleDelta) / totalDelta) * 100, 0, 100);\n\t\t\t}\n\t\t\tthis.prevSysCpu = sys;\n\t\t}\n\t\tconst sysMem = this.readSystemMemory();\n\t\tthis.systemMemoryTotalBytes = sysMem.total;\n\t\tthis.systemMemoryUsedBytes = Math.max(0, sysMem.total - sysMem.free);\n\n\t\tthis.smoothedHistory.push(smoothed);\n\t\tif (this.smoothedHistory.length > this.historySize) {\n\t\t\tthis.smoothedHistory.shift();\n\t\t}\n\t\tif (this.cpuPeak === null || smoothed > this.cpuPeak) {\n\t\t\tthis.cpuPeak = smoothed;\n\t\t}\n\t\tconst isCpuSpike = smoothed > this.spikeThreshold;\n\t\tif (isCpuSpike && !this.wasCpuSpike) {\n\t\t\tthis.cpuSpikeCount++;\n\t\t}\n\t\tthis.wasCpuSpike = isCpuSpike;\n\n\t\t// Accumulate the delta so the next sample computes from the same baseline.\n\t\tthis.prevCpu = {\n\t\t\tuser: this.prevCpu.user + delta.user,\n\t\t\tsystem: this.prevCpu.system + delta.system,\n\t\t};\n\t\tthis.prevTime = now;\n\t}\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\n/** Aggregate os.cpus() times into { idle, total } jiffies (ms) across all cores. */\nfunction readOsCpuTimes(): { idle: number; total: number } {\n\tlet idle = 0;\n\tlet total = 0;\n\tfor (const cpu of os.cpus()) {\n\t\tidle += cpu.times.idle;\n\t\ttotal += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq;\n\t}\n\treturn { idle, total };\n}\n\nfunction sanitizeNumber(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn clamp(value, min, max);\n}\n\nfunction sanitizeInteger(value: unknown, fallback: number, min: number, max: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(clamp(value, min, max));\n}\n"]}