repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * Heartbeat Configuration |
| #3 | * |
| #4 | * Parses and manages heartbeat.yml configuration. |
| #5 | */ |
| #6 | import fs from "fs"; |
| #7 | import path from "path"; |
| #8 | import YAML from "yaml"; |
| #9 | import { getAutomatonDir } from "../identity/wallet.js"; |
| #10 | const USDC_TOPUP_ENTRY_NAME = "check_usdc_balance"; |
| #11 | const USDC_TOPUP_FAST_SCHEDULE = "*/5 * * * *"; |
| #12 | const USDC_TOPUP_OLD_SCHEDULE = "0 */12 * * *"; |
| #13 | const DEFAULT_HEARTBEAT_CONFIG = { |
| #14 | entries: [ |
| #15 | { |
| #16 | name: "heartbeat_ping", |
| #17 | schedule: "*/15 * * * *", |
| #18 | task: "heartbeat_ping", |
| #19 | enabled: true, |
| #20 | }, |
| #21 | { |
| #22 | name: "check_credits", |
| #23 | schedule: "0 */6 * * *", |
| #24 | task: "check_credits", |
| #25 | enabled: true, |
| #26 | }, |
| #27 | { |
| #28 | name: "check_usdc_balance", |
| #29 | schedule: USDC_TOPUP_FAST_SCHEDULE, |
| #30 | task: "check_usdc_balance", |
| #31 | enabled: true, |
| #32 | }, |
| #33 | { |
| #34 | name: "check_for_updates", |
| #35 | schedule: "0 */4 * * *", |
| #36 | task: "check_for_updates", |
| #37 | enabled: true, |
| #38 | }, |
| #39 | { |
| #40 | name: "health_check", |
| #41 | schedule: "*/30 * * * *", |
| #42 | task: "health_check", |
| #43 | enabled: true, |
| #44 | }, |
| #45 | { |
| #46 | name: "convex_heartbeat", |
| #47 | schedule: "*/2 * * * *", |
| #48 | task: "convex_heartbeat", |
| #49 | enabled: true, |
| #50 | }, |
| #51 | { |
| #52 | name: "check_social_inbox", |
| #53 | schedule: "*/2 * * * *", |
| #54 | task: "check_social_inbox", |
| #55 | enabled: true, |
| #56 | }, |
| #57 | { |
| #58 | name: "backroom_conversation", |
| #59 | schedule: "0 */2 * * *", |
| #60 | task: "backroom_conversation", |
| #61 | enabled: true, |
| #62 | }, |
| #63 | ], |
| #64 | defaultIntervalMs: 60_000, |
| #65 | lowComputeMultiplier: 4, |
| #66 | }; |
| #67 | /** |
| #68 | * Load heartbeat config from YAML file, falling back to defaults. |
| #69 | */ |
| #70 | export function loadHeartbeatConfig(configPath) { |
| #71 | const filePath = configPath || path.join(getAutomatonDir(), "heartbeat.yml"); |
| #72 | if (!fs.existsSync(filePath)) { |
| #73 | return DEFAULT_HEARTBEAT_CONFIG; |
| #74 | } |
| #75 | try { |
| #76 | const raw = fs.readFileSync(filePath, "utf-8"); |
| #77 | const parsed = YAML.parse(raw) || {}; |
| #78 | const parsedEntries = (parsed.entries || []).map((e) => ({ |
| #79 | name: e.name, |
| #80 | schedule: e.schedule, |
| #81 | task: e.task, |
| #82 | enabled: e.enabled !== false, |
| #83 | params: e.params, |
| #84 | })); |
| #85 | const entries = mergeWithDefaults(parsedEntries); |
| #86 | return { |
| #87 | entries, |
| #88 | defaultIntervalMs: parsed.defaultIntervalMs || DEFAULT_HEARTBEAT_CONFIG.defaultIntervalMs, |
| #89 | lowComputeMultiplier: parsed.lowComputeMultiplier || |
| #90 | DEFAULT_HEARTBEAT_CONFIG.lowComputeMultiplier, |
| #91 | }; |
| #92 | } |
| #93 | catch { |
| #94 | return DEFAULT_HEARTBEAT_CONFIG; |
| #95 | } |
| #96 | } |
| #97 | /** |
| #98 | * Save heartbeat config to YAML file. |
| #99 | */ |
| #100 | export function saveHeartbeatConfig(config, configPath) { |
| #101 | const filePath = configPath || path.join(getAutomatonDir(), "heartbeat.yml"); |
| #102 | const dir = path.dirname(filePath); |
| #103 | if (!fs.existsSync(dir)) { |
| #104 | fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); |
| #105 | } |
| #106 | fs.writeFileSync(filePath, YAML.stringify(config), { mode: 0o600 }); |
| #107 | } |
| #108 | /** |
| #109 | * Write the default heartbeat.yml file. |
| #110 | */ |
| #111 | export function writeDefaultHeartbeatConfig(configPath) { |
| #112 | saveHeartbeatConfig(DEFAULT_HEARTBEAT_CONFIG, configPath); |
| #113 | } |
| #114 | /** |
| #115 | * Sync heartbeat entries from YAML config into the database. |
| #116 | */ |
| #117 | export function syncHeartbeatToDb(config, db) { |
| #118 | for (const entry of config.entries) { |
| #119 | db.upsertHeartbeatEntry(entry); |
| #120 | } |
| #121 | } |
| #122 | function mergeWithDefaults(entries) { |
| #123 | const defaults = DEFAULT_HEARTBEAT_CONFIG.entries.map((entry) => ({ ...entry })); |
| #124 | const defaultsByName = new Map(defaults.map((entry) => [entry.name, entry])); |
| #125 | const mergedByName = new Map(defaultsByName); |
| #126 | for (const entry of entries) { |
| #127 | if (!entry?.name) |
| #128 | continue; |
| #129 | const fallback = defaultsByName.get(entry.name); |
| #130 | mergedByName.set(entry.name, { |
| #131 | ...(fallback || {}), |
| #132 | ...entry, |
| #133 | enabled: entry.enabled !== false, |
| #134 | task: entry.task || fallback?.task || "", |
| #135 | schedule: entry.schedule || fallback?.schedule || "", |
| #136 | }); |
| #137 | } |
| #138 | const fallbackTopup = defaultsByName.get(USDC_TOPUP_ENTRY_NAME); |
| #139 | if (fallbackTopup) { |
| #140 | const current = mergedByName.get(USDC_TOPUP_ENTRY_NAME) || fallbackTopup; |
| #141 | const migratedSchedule = current.schedule?.trim() === USDC_TOPUP_OLD_SCHEDULE |
| #142 | ? USDC_TOPUP_FAST_SCHEDULE |
| #143 | : current.schedule || fallbackTopup.schedule; |
| #144 | mergedByName.set(USDC_TOPUP_ENTRY_NAME, { |
| #145 | ...fallbackTopup, |
| #146 | ...current, |
| #147 | task: current.task || fallbackTopup.task, |
| #148 | schedule: migratedSchedule, |
| #149 | }); |
| #150 | } |
| #151 | const orderedDefaultEntries = defaults.map((defaultEntry) => mergedByName.get(defaultEntry.name) || defaultEntry); |
| #152 | const knownNames = new Set(defaults.map((entry) => entry.name)); |
| #153 | const customEntries = [...mergedByName.values()].filter((entry) => !knownNames.has(entry.name)); |
| #154 | return [...orderedDefaultEntries, ...customEntries]; |
| #155 | } |
| #156 | //# sourceMappingURL=config.js.map |