@openlife/cli 1.7.3

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 (394) hide show
  1. package/INSTALL.md +266 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -0
  4. package/bin/openlife.js +3 -0
  5. package/dist/admin_panel_server.js +66 -0
  6. package/dist/cli/AgentManager.js +109 -0
  7. package/dist/cli/AutonomousInstaller.js +134 -0
  8. package/dist/cli/DreamOrganizer.js +88 -0
  9. package/dist/cli/HostInstaller.js +426 -0
  10. package/dist/cli/InstallBanner.js +16 -0
  11. package/dist/cli/InstallFlow.js +256 -0
  12. package/dist/cli/InstallHeadless.js +47 -0
  13. package/dist/cli/InstallModules.js +148 -0
  14. package/dist/cli/InstallStateStore.js +75 -0
  15. package/dist/cli/InstallWizard.js +364 -0
  16. package/dist/cli/ProfileManager.js +163 -0
  17. package/dist/cli/SystemInstaller.js +89 -0
  18. package/dist/cli/WorldClassCommands.js +208 -0
  19. package/dist/design/DesignMdImporter.js +82 -0
  20. package/dist/design/DesignMdMode.js +93 -0
  21. package/dist/design/DesignMdRegistry.js +67 -0
  22. package/dist/index.js +2575 -0
  23. package/dist/memory/ConversationMemory.js +33 -0
  24. package/dist/memory/LocalMemoryProvider.js +86 -0
  25. package/dist/memory/Mem0Provider.js +16 -0
  26. package/dist/memory/MemoryNamespacePolicy.js +27 -0
  27. package/dist/memory/MemoryOrchestrator.js +65 -0
  28. package/dist/memory/MemoryPromotionFlow.js +32 -0
  29. package/dist/memory/MemoryProvider.js +2 -0
  30. package/dist/memory/MemoryProviderRegistry.js +27 -0
  31. package/dist/memory/MemoryRetentionPolicy.js +60 -0
  32. package/dist/memory/MempalaceProvider.js +72 -0
  33. package/dist/memory/OmniMemory.js +106 -0
  34. package/dist/memory/RedisAgentMemoryProvider.js +16 -0
  35. package/dist/memory/SessionManager.js +86 -0
  36. package/dist/memory/ZepGraphitiProvider.js +16 -0
  37. package/dist/orchestrator/AgentRegistry.js +56 -0
  38. package/dist/orchestrator/AgentScoring.js +82 -0
  39. package/dist/orchestrator/AgentTeam.js +22 -0
  40. package/dist/orchestrator/ArbitrationAgent.js +43 -0
  41. package/dist/orchestrator/ArbitrationScorecard.js +17 -0
  42. package/dist/orchestrator/AssetPromotionEngine.js +65 -0
  43. package/dist/orchestrator/AssetReuseRouter.js +63 -0
  44. package/dist/orchestrator/BenchmarkEngine.js +75 -0
  45. package/dist/orchestrator/Brain.js +298 -0
  46. package/dist/orchestrator/CadenceEngine.js +76 -0
  47. package/dist/orchestrator/CapabilityRouter.js +36 -0
  48. package/dist/orchestrator/CommandLanguage.js +27 -0
  49. package/dist/orchestrator/CommandRouter.js +70 -0
  50. package/dist/orchestrator/ConsequenceForecaster.js +286 -0
  51. package/dist/orchestrator/CronManager.js +286 -0
  52. package/dist/orchestrator/DynamicAgentBuilder.js +48 -0
  53. package/dist/orchestrator/DynamicAgentExecutor.js +15 -0
  54. package/dist/orchestrator/EnterpriseAgenticCore.js +276 -0
  55. package/dist/orchestrator/ExecutionBoard.js +86 -0
  56. package/dist/orchestrator/ExecutionIntent.js +13 -0
  57. package/dist/orchestrator/ExecutionModePolicy.js +48 -0
  58. package/dist/orchestrator/ExecutionRouter.js +9 -0
  59. package/dist/orchestrator/ExecutionState.js +20 -0
  60. package/dist/orchestrator/ExecutorHealth.js +86 -0
  61. package/dist/orchestrator/ExternalCatalogRegistry.js +83 -0
  62. package/dist/orchestrator/Gatekeeper.js +414 -0
  63. package/dist/orchestrator/Gateway.js +508 -0
  64. package/dist/orchestrator/GovernanceConsentStore.js +66 -0
  65. package/dist/orchestrator/GovernanceLayer.js +179 -0
  66. package/dist/orchestrator/GovernancePolicyStore.js +53 -0
  67. package/dist/orchestrator/GovernanceScopeLedger.js +134 -0
  68. package/dist/orchestrator/GovernanceScopePolicy.js +67 -0
  69. package/dist/orchestrator/IntentClassifier.js +45 -0
  70. package/dist/orchestrator/JobLifecycle.js +91 -0
  71. package/dist/orchestrator/LearningRouter.js +24 -0
  72. package/dist/orchestrator/MediaManager.js +92 -0
  73. package/dist/orchestrator/MemoryCuratorAgent.js +41 -0
  74. package/dist/orchestrator/MissionState.js +155 -0
  75. package/dist/orchestrator/ModelManager.js +84 -0
  76. package/dist/orchestrator/OperatingSystem.js +71 -0
  77. package/dist/orchestrator/OperationalMemoryStore.js +94 -0
  78. package/dist/orchestrator/OptimizationLoop.js +72 -0
  79. package/dist/orchestrator/OrchestrationLoop.js +905 -0
  80. package/dist/orchestrator/OrgStructure.js +88 -0
  81. package/dist/orchestrator/OutcomeSimulator.js +46 -0
  82. package/dist/orchestrator/ParallelOrchestrationLoop.js +36 -0
  83. package/dist/orchestrator/PerformanceScorecard.js +105 -0
  84. package/dist/orchestrator/PlannerAgent.js +46 -0
  85. package/dist/orchestrator/ProcessSandbox.js +129 -0
  86. package/dist/orchestrator/PromotionPipeline.js +74 -0
  87. package/dist/orchestrator/PromotionReviewGate.js +11 -0
  88. package/dist/orchestrator/QueueScheduler.js +260 -0
  89. package/dist/orchestrator/ReleaseGate.js +36 -0
  90. package/dist/orchestrator/ReleaseWorkflow.js +68 -0
  91. package/dist/orchestrator/RemotePublisher.js +139 -0
  92. package/dist/orchestrator/ReuseEngine.js +89 -0
  93. package/dist/orchestrator/ReviewerAgent.js +49 -0
  94. package/dist/orchestrator/RoleHandoff.js +65 -0
  95. package/dist/orchestrator/RuntimeHealthMonitor.js +143 -0
  96. package/dist/orchestrator/RuntimePolicy.js +105 -0
  97. package/dist/orchestrator/RuntimeProbe.js +97 -0
  98. package/dist/orchestrator/RuntimeRegistry.js +73 -0
  99. package/dist/orchestrator/SandboxPolicy.js +22 -0
  100. package/dist/orchestrator/SecurityDownloadGuard.js +169 -0
  101. package/dist/orchestrator/SecurityEventStore.js +58 -0
  102. package/dist/orchestrator/ServiceCompletionPolicy.js +36 -0
  103. package/dist/orchestrator/ServiceState.js +195 -0
  104. package/dist/orchestrator/SkillCreator.js +404 -0
  105. package/dist/orchestrator/SkillLearningLoop.js +57 -0
  106. package/dist/orchestrator/SkillManager.js +75 -0
  107. package/dist/orchestrator/SkillNetwork.js +29 -0
  108. package/dist/orchestrator/SkillRegistryV2.js +28 -0
  109. package/dist/orchestrator/SkillScoring.js +70 -0
  110. package/dist/orchestrator/SquadAutoCreator.js +64 -0
  111. package/dist/orchestrator/SquadCreator.js +727 -0
  112. package/dist/orchestrator/SquadRegistry.js +28 -0
  113. package/dist/orchestrator/SquadRouter.js +33 -0
  114. package/dist/orchestrator/SquadScoring.js +70 -0
  115. package/dist/orchestrator/SubagentLifecycle.js +90 -0
  116. package/dist/orchestrator/SynthesizerAgent.js +48 -0
  117. package/dist/orchestrator/SystemDoctor.js +224 -0
  118. package/dist/orchestrator/TaskExecutor.js +422 -0
  119. package/dist/orchestrator/TeammateBoard.js +61 -0
  120. package/dist/orchestrator/TestHarness.js +184 -0
  121. package/dist/orchestrator/VoiceManager.js +203 -0
  122. package/dist/orchestrator/VoiceRouter.js +89 -0
  123. package/dist/orchestrator/capability/CapabilityGenesisEngine.js +278 -0
  124. package/dist/orchestrator/capability/CapabilityPackParser.js +223 -0
  125. package/dist/orchestrator/capability/CapabilityPackSchema.js +62 -0
  126. package/dist/orchestrator/capability/CapabilityPackState.js +163 -0
  127. package/dist/orchestrator/providers/AgentProvider.js +2 -0
  128. package/dist/orchestrator/providers/CapabilityProvider.js +12 -0
  129. package/dist/orchestrator/providers/CloudAgentProvider.js +55 -0
  130. package/dist/orchestrator/providers/CloudSkillProvider.js +55 -0
  131. package/dist/orchestrator/providers/CloudSquadProvider.js +55 -0
  132. package/dist/orchestrator/providers/CompositeAgentProvider.js +16 -0
  133. package/dist/orchestrator/providers/CompositeCapabilityProvider.js +25 -0
  134. package/dist/orchestrator/providers/CompositeSkillProvider.js +16 -0
  135. package/dist/orchestrator/providers/CompositeSquadProvider.js +16 -0
  136. package/dist/orchestrator/providers/CompositeWorkflowProvider.js +46 -0
  137. package/dist/orchestrator/providers/FileAgentProvider.js +105 -0
  138. package/dist/orchestrator/providers/FileCapabilityProvider.js +106 -0
  139. package/dist/orchestrator/providers/FileSkillProvider.js +65 -0
  140. package/dist/orchestrator/providers/FileSquadProvider.js +69 -0
  141. package/dist/orchestrator/providers/FileWorkflowProvider.js +103 -0
  142. package/dist/orchestrator/providers/SkillProvider.js +2 -0
  143. package/dist/orchestrator/providers/SquadProvider.js +2 -0
  144. package/dist/orchestrator/toolset/ToolsetGuard.js +69 -0
  145. package/dist/orchestrator/toolset/ToolsetRegistry.js +65 -0
  146. package/dist/orchestrator/toolset/ToolsetSchema.js +21 -0
  147. package/dist/orchestrator/util/AtomicWriter.js +204 -0
  148. package/dist/orchestrator/util/DistributedLock.js +232 -0
  149. package/dist/orchestrator/util/TemplateRenderer.js +87 -0
  150. package/dist/orchestrator/util/WatchdogHeartbeat.js +116 -0
  151. package/dist/orchestrator/workflow/ConditionParser.js +232 -0
  152. package/dist/orchestrator/workflow/WorkflowEngine.js +379 -0
  153. package/dist/orchestrator/workflow/WorkflowParser.js +368 -0
  154. package/dist/orchestrator/workflow/WorkflowSchema.js +65 -0
  155. package/dist/orchestrator/workflow/WorkflowState.js +11 -0
  156. package/dist/reversa/ReversaAgent.js +134 -0
  157. package/dist/reversa/ReversaContracts.js +62 -0
  158. package/dist/reversa/ReversaExecutors.js +65 -0
  159. package/dist/skills/SkillRegistry.js +71 -0
  160. package/dist/squads/SquadManager.js +87 -0
  161. package/dist/test_admin_teams_networks.js +54 -0
  162. package/dist/test_agent_team_skill_network.js +15 -0
  163. package/dist/test_aiobuilder_cli_parity.js +169 -0
  164. package/dist/test_ask_exit.js +73 -0
  165. package/dist/test_atomic_writer.js +209 -0
  166. package/dist/test_autonomous_soak.js +141 -0
  167. package/dist/test_benchmark_engine.js +41 -0
  168. package/dist/test_brain_error_diagnostics.js +51 -0
  169. package/dist/test_brain_fallback_chain.js +93 -0
  170. package/dist/test_capability_genesis_engine.js +225 -0
  171. package/dist/test_capability_pack_schema.js +214 -0
  172. package/dist/test_catalog_quality.js +150 -0
  173. package/dist/test_cli_crud_roundtrip.js +154 -0
  174. package/dist/test_cli_diagnostics.js +131 -0
  175. package/dist/test_cli_doc_parity.js +126 -0
  176. package/dist/test_cli_help_surface.js +106 -0
  177. package/dist/test_cli_service_commands.js +83 -0
  178. package/dist/test_consequence_forecast_brain.js +165 -0
  179. package/dist/test_consequence_forecaster.js +24 -0
  180. package/dist/test_conversation_memory.js +36 -0
  181. package/dist/test_create_entities.js +54 -0
  182. package/dist/test_creator_placeholders_completed.js +177 -0
  183. package/dist/test_cron_manager.js +123 -0
  184. package/dist/test_daemon_sigterm.js +72 -0
  185. package/dist/test_deep_research_capability.js +87 -0
  186. package/dist/test_designmd_import_registry.js +16 -0
  187. package/dist/test_designmd_mode.js +50 -0
  188. package/dist/test_designmd_mode_workspace.js +13 -0
  189. package/dist/test_dist_templates_layout.js +135 -0
  190. package/dist/test_distributed_lock.js +201 -0
  191. package/dist/test_distribution_installability.js +67 -0
  192. package/dist/test_doctor_sandbox_check.js +44 -0
  193. package/dist/test_dream_organizer.js +25 -0
  194. package/dist/test_dual_mode.js +15 -0
  195. package/dist/test_enterprise_agentic_core.js +128 -0
  196. package/dist/test_forecast_brain_wiring.js +87 -0
  197. package/dist/test_gateway_telegram_guardrails.js +52 -0
  198. package/dist/test_governance.js +34 -0
  199. package/dist/test_governance_advanced.js +75 -0
  200. package/dist/test_governance_scope_ledger.js +147 -0
  201. package/dist/test_governance_v13_policies.js +44 -0
  202. package/dist/test_guided_creator_cli.js +100 -0
  203. package/dist/test_host_install_e2e.js +324 -0
  204. package/dist/test_host_installer.js +259 -0
  205. package/dist/test_host_installers_gemini_codex.js +95 -0
  206. package/dist/test_host_uninstaller.js +295 -0
  207. package/dist/test_install_flow.js +70 -0
  208. package/dist/test_install_flow_host_validation.js +143 -0
  209. package/dist/test_install_wizard.js +272 -0
  210. package/dist/test_integration_gemini_live.js +95 -0
  211. package/dist/test_integration_http_trigger_live.js +154 -0
  212. package/dist/test_integration_telegram_live.js +102 -0
  213. package/dist/test_job_lifecycle.js +16 -0
  214. package/dist/test_memory_orchestrator.js +33 -0
  215. package/dist/test_memory_promotion.js +36 -0
  216. package/dist/test_memory_retention.js +37 -0
  217. package/dist/test_mission_checkpoint.js +204 -0
  218. package/dist/test_multi_host_docs_parity.js +125 -0
  219. package/dist/test_openlife_auto_creator_routing.js +69 -0
  220. package/dist/test_openlife_evolution_surface.js +77 -0
  221. package/dist/test_openlife_gatekeeper_routing.js +15 -0
  222. package/dist/test_openlife_routing_surface.js +27 -0
  223. package/dist/test_openlife_runtime_source_truth.js +25 -0
  224. package/dist/test_operating_system.js +45 -0
  225. package/dist/test_optimization_loop.js +38 -0
  226. package/dist/test_orchestration_assets_lifecycle.js +78 -0
  227. package/dist/test_outcome_simulator.js +38 -0
  228. package/dist/test_performance_latency.js +215 -0
  229. package/dist/test_performance_scorecard.js +38 -0
  230. package/dist/test_phase1_check_exit.js +103 -0
  231. package/dist/test_phase6_board.js +31 -0
  232. package/dist/test_phase6_cadence.js +29 -0
  233. package/dist/test_phase6_ops.js +37 -0
  234. package/dist/test_post_mission_evaluation.js +190 -0
  235. package/dist/test_process_sandbox.js +88 -0
  236. package/dist/test_profile_toolset_mcp.js +125 -0
  237. package/dist/test_queue_scheduler.js +239 -0
  238. package/dist/test_release_gate.js +23 -0
  239. package/dist/test_remote_publish.js +193 -0
  240. package/dist/test_reversa_contracts_e2e.js +48 -0
  241. package/dist/test_reversa_export_and_strict.js +51 -0
  242. package/dist/test_reversa_full_execution.js +12 -0
  243. package/dist/test_reversa_lite.js +9 -0
  244. package/dist/test_royal_stack_golden.js +179 -0
  245. package/dist/test_runtime_health_backoff.js +154 -0
  246. package/dist/test_runtime_policy.js +26 -0
  247. package/dist/test_runtime_probe.js +19 -0
  248. package/dist/test_runtime_profile_oauth_only.js +262 -0
  249. package/dist/test_runtime_registry.js +11 -0
  250. package/dist/test_security_download_and_scan.js +103 -0
  251. package/dist/test_security_download_guard.js +14 -0
  252. package/dist/test_service_command_surface.js +12 -0
  253. package/dist/test_service_completion_policy.js +32 -0
  254. package/dist/test_service_guardrails_delete.js +12 -0
  255. package/dist/test_service_mode_explicit_only.js +174 -0
  256. package/dist/test_sources_import_ref.js +46 -0
  257. package/dist/test_sources_scaffold.js +43 -0
  258. package/dist/test_squad_skill_creator.js +305 -0
  259. package/dist/test_squad_skill_design_llm.js +176 -0
  260. package/dist/test_subsystems_org_state.js +271 -0
  261. package/dist/test_subsystems_promotion_memory_assets.js +343 -0
  262. package/dist/test_subsystems_routing_governance.js +234 -0
  263. package/dist/test_task_executor_sandbox_optin.js +127 -0
  264. package/dist/test_teammate_learning.js +15 -0
  265. package/dist/test_telegram_delete_guardrail.js +21 -0
  266. package/dist/test_toolset_enforcement.js +188 -0
  267. package/dist/test_trigger_basic_auth.js +112 -0
  268. package/dist/test_util/doc_parity.js +120 -0
  269. package/dist/test_v15_e2e_integration.js +207 -0
  270. package/dist/test_watchdog_heartbeat.js +152 -0
  271. package/dist/test_workflow_condition_parser.js +63 -0
  272. package/dist/test_workflow_e2e.js +240 -0
  273. package/dist/test_workflow_engine.js +330 -0
  274. package/dist/test_workflow_parser.js +245 -0
  275. package/dist/test_workflow_schema_backward_compat.js +197 -0
  276. package/dist-templates/README.md +91 -0
  277. package/dist-templates/claude-code/agents/openlife-atlas.md +52 -0
  278. package/dist-templates/claude-code/agents/openlife-forge.md +42 -0
  279. package/dist-templates/claude-code/agents/openlife-genesis.md +59 -0
  280. package/dist-templates/claude-code/agents/openlife-lyra.md +40 -0
  281. package/dist-templates/claude-code/agents/openlife-maestro.md +45 -0
  282. package/dist-templates/claude-code/commands/openlife/ask.md +14 -0
  283. package/dist-templates/claude-code/commands/openlife/doctor.md +19 -0
  284. package/dist-templates/claude-code/commands/openlife/dream.md +20 -0
  285. package/dist-templates/claude-code/commands/openlife/status.md +14 -0
  286. package/dist-templates/claude-code/mcp/openlife-orchestrator.json +46 -0
  287. package/dist-templates/codex/README.md +7 -0
  288. package/dist-templates/codex/agents/openlife-atlas.md +52 -0
  289. package/dist-templates/codex/agents/openlife-forge.md +42 -0
  290. package/dist-templates/codex/agents/openlife-genesis.md +59 -0
  291. package/dist-templates/codex/agents/openlife-lyra.md +40 -0
  292. package/dist-templates/codex/agents/openlife-maestro.md +45 -0
  293. package/dist-templates/codex/commands/openlife/ask.md +14 -0
  294. package/dist-templates/codex/commands/openlife/doctor.md +19 -0
  295. package/dist-templates/codex/commands/openlife/dream.md +20 -0
  296. package/dist-templates/codex/commands/openlife/status.md +14 -0
  297. package/dist-templates/codex/mcp/openlife-orchestrator.json +46 -0
  298. package/dist-templates/gemini-cli/README.md +8 -0
  299. package/dist-templates/gemini-cli/agents/openlife-atlas.md +52 -0
  300. package/dist-templates/gemini-cli/agents/openlife-forge.md +42 -0
  301. package/dist-templates/gemini-cli/agents/openlife-genesis.md +59 -0
  302. package/dist-templates/gemini-cli/agents/openlife-lyra.md +40 -0
  303. package/dist-templates/gemini-cli/agents/openlife-maestro.md +45 -0
  304. package/dist-templates/gemini-cli/commands/openlife/ask.md +14 -0
  305. package/dist-templates/gemini-cli/commands/openlife/doctor.md +19 -0
  306. package/dist-templates/gemini-cli/commands/openlife/dream.md +20 -0
  307. package/dist-templates/gemini-cli/commands/openlife/status.md +14 -0
  308. package/dist-templates/gemini-cli/mcp/openlife-orchestrator.json +46 -0
  309. package/dist-templates/skill-template/README.md +34 -0
  310. package/dist-templates/skill-template/SKILL.md.template +59 -0
  311. package/dist-templates/squad-template/README.md +82 -0
  312. package/dist-templates/squad-template/SQUAD.md.template +51 -0
  313. package/dist-templates/squad-template/agent-template.md +51 -0
  314. package/dist-templates/squad-template/checklist-template.md +25 -0
  315. package/dist-templates/squad-template/task-template.md +36 -0
  316. package/dist-templates/workflows/PORTED_WORKFLOWS.md +60 -0
  317. package/dist-templates/workflows/brownfield-discovery.yaml +137 -0
  318. package/dist-templates/workflows/greenfield-fullstack.yaml +132 -0
  319. package/dist-templates/workflows/qa-loop.yaml +125 -0
  320. package/dist-templates/workflows/story-development-cycle.yaml +80 -0
  321. package/docs/CHANGELOG_FEATURE_ROLLOUT_DESIGNMD.md +43 -0
  322. package/docs/EXTERNAL_SOURCES_AND_SECURITY_GUARD.md +33 -0
  323. package/docs/OPENLIFE_AUDIT_2026-05-06.md +170 -0
  324. package/docs/OPENLIFE_CONSOLIDATED_PLAN_2026-05-06.md +299 -0
  325. package/docs/OPENLIFE_DUAL_MODE_IMPLEMENTATION_PLAN.md +205 -0
  326. package/docs/OPENLIFE_EVOLUTION_SURFACE_2026-05-07.md +53 -0
  327. package/docs/OPENLIFE_SKILLS_IMPORT_2026-05-07.json +223 -0
  328. package/docs/OPENLIFE_SQUADS_IMPORT_2026-05-07.json +184 -0
  329. package/docs/PAPERCLIP_OPENLIFE_INVESTIGATION.md +85 -0
  330. package/docs/README.md +28 -0
  331. package/docs/RELEASE_ORGANIZATION_PLAN.md +164 -0
  332. package/docs/audit/CLI-EXECUTION-RESULTS.md +113 -0
  333. package/docs/audit/CLI-MATRIX.md +556 -0
  334. package/docs/audit/DOC-PARITY-GAPS.md +351 -0
  335. package/docs/audit/ORCHESTRATOR-MATRIX.md +136 -0
  336. package/docs/audit/TEST-COVERAGE-GAPS.md +334 -0
  337. package/docs/audit/integrations/SKIPPED.md +101 -0
  338. package/docs/autonomous-install.md +79 -0
  339. package/docs/capability-genesis.md +137 -0
  340. package/docs/capability-pack-schema.md +157 -0
  341. package/docs/commands.md +82 -0
  342. package/docs/deep-research-capability.md +114 -0
  343. package/docs/development/typescript-conventions.md +95 -0
  344. package/docs/host-installers.md +68 -0
  345. package/docs/install/aiobuilder.md +70 -0
  346. package/docs/install/claude-code.md +83 -0
  347. package/docs/install/codex.md +64 -0
  348. package/docs/install/gemini-cli.md +64 -0
  349. package/docs/install/runtime-profiles.md +83 -0
  350. package/docs/openlife-agent-os-blueprint.md +114 -0
  351. package/docs/openlife-install-backlog.md +115 -0
  352. package/docs/openlife-install-spec.md +306 -0
  353. package/docs/operations/CLOUD_CUTOVER_AUDIT.md +37 -0
  354. package/docs/operations/PHASE_PROGRESS_CONTINUATION.md +24 -0
  355. package/docs/performance-benchmarks.md +83 -0
  356. package/docs/planning/v1.3-capability-genesis.md +157 -0
  357. package/docs/plans/2026-05-05-admin-interface-professional-dark-premium-plan.md +84 -0
  358. package/docs/plans/2026-05-05-openlife-autonomous-domain-marketplace-masterplan.md +122 -0
  359. package/docs/quickstart.md +60 -0
  360. package/docs/release-process.md +236 -0
  361. package/docs/roadmap/OPENLIFE_MASTER_PLAN_CLOUD_V3.md +97 -0
  362. package/docs/sandboxing-research.md +117 -0
  363. package/docs/stories/epic-feature-audit/1.1.story.md +84 -0
  364. package/docs/stories/epic-feature-audit/1.2.story.md +102 -0
  365. package/docs/stories/epic-feature-audit/1.3.story.md +93 -0
  366. package/docs/stories/epic-feature-audit/1.5.story.md +121 -0
  367. package/docs/stories/epic-feature-audit/1.6.story.md +80 -0
  368. package/docs/stories/epic-feature-completeness/2.1.story.md +70 -0
  369. package/docs/stories/epic-feature-completeness/2.2.story.md +49 -0
  370. package/docs/stories/epic-feature-completeness/2.3.story.md +74 -0
  371. package/docs/stories/epic-feature-completeness/2.4.story.md +71 -0
  372. package/docs/stories/epic-feature-completeness/3.1.story.md +56 -0
  373. package/docs/stories/epic-feature-completeness/3.2.story.md +80 -0
  374. package/docs/stories/epic-feature-completeness/3.3.story.md +68 -0
  375. package/docs/stories/epic-feature-completeness/3.4.story.md +71 -0
  376. package/docs/stories/epic-feature-completeness/3.5.story.md +72 -0
  377. package/docs/stories/epic-feature-completeness/3.6.story.md +69 -0
  378. package/docs/stories/epic-feature-completeness/3.7.story.md +68 -0
  379. package/docs/stories/epic-feature-completeness/3.8.story.md +57 -0
  380. package/docs/toolset-enforcement.md +122 -0
  381. package/docs/v1.4-changelog.md +159 -0
  382. package/docs/v1.5-changelog.md +106 -0
  383. package/docs/v1.5-roadmap.md +121 -0
  384. package/docs/v1.6-changelog.md +67 -0
  385. package/docs/v1.6-roadmap.md +89 -0
  386. package/docs/v1.7-changelog.md +98 -0
  387. package/docs/workflow-schema.md +177 -0
  388. package/package.json +177 -0
  389. package/scripts/clean-test-pollution.js +61 -0
  390. package/scripts/openlife-agent-start.sh +6 -0
  391. package/scripts/openlife-agent.service.example +13 -0
  392. package/scripts/openlife-agent.supervisord.conf.example +8 -0
  393. package/scripts/openlife-autonomous-install.sh +29 -0
  394. package/scripts/postinstall-check.sh +37 -0
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * ToolsetSchema — toolset categories + per-profile allow/deny lists.
4
+ *
5
+ * Story 5.3 — OpenLife v1.3 Agent OS Integration.
6
+ *
7
+ * A Toolset is a named category of tools an agent might want to use.
8
+ * Profiles allowlist toolsets; the runtime enforcement point (Gatekeeper)
9
+ * checks before dispatch.
10
+ *
11
+ * v1.3 ships the registry + decision API. Actual kernel-level
12
+ * enforcement of fs/bash inside executor sandboxes is v1.4.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ALL_TOOLSETS = void 0;
16
+ exports.ALL_TOOLSETS = [
17
+ 'file', 'terminal', 'web', 'browser',
18
+ 'memory', 'skills', 'workflows', 'squads',
19
+ 'gateway', 'cron', 'delegation', 'mcp',
20
+ 'vision', 'tts', 'image_gen',
21
+ ];
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * AtomicWriter — crash-safe persistence helpers for OpenLife state files.
4
+ *
5
+ * Pattern:
6
+ * 1. Write payload to `<filePath>.tmp.<pid>.<ts>`
7
+ * 2. fsync the temp file (flush OS buffer to disk)
8
+ * 3. Atomically rename temp → final (single syscall on POSIX, MoveFileEx on Windows)
9
+ * 4. On any error: best-effort cleanup of temp file
10
+ *
11
+ * The rename step is atomic per the OS (POSIX rename(2), NTFS MoveFile), so a
12
+ * `kill -9` mid-operation leaves either the old file intact, or the fully new
13
+ * one. There is no partial-write window observable by other processes.
14
+ *
15
+ * Concurrency: each writer uses a unique temp suffix (`pid.ts.rand`), so
16
+ * multiple processes writing the same final path do not collide on the temp.
17
+ * The final rename is last-writer-wins, which is acceptable for our state
18
+ * files (the loser's data is discarded, not corrupted).
19
+ *
20
+ * Feature flag: `OPENLIFE_ATOMIC_WRITES=off` disables atomicity and falls
21
+ * back to plain writeFileSync / appendFileSync. Default is 'on'.
22
+ *
23
+ * Story 6.1 — OpenLife v1.2 Royal Stack.
24
+ */
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
37
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
38
+ }) : function(o, v) {
39
+ o["default"] = v;
40
+ });
41
+ var __importStar = (this && this.__importStar) || (function () {
42
+ var ownKeys = function(o) {
43
+ ownKeys = Object.getOwnPropertyNames || function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54
+ __setModuleDefault(result, mod);
55
+ return result;
56
+ };
57
+ })();
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.writeJsonAtomic = writeJsonAtomic;
60
+ exports.writeStringAtomic = writeStringAtomic;
61
+ exports.appendJsonlAtomic = appendJsonlAtomic;
62
+ exports.appendStringAtomic = appendStringAtomic;
63
+ exports.purgeStaleTempFiles = purgeStaleTempFiles;
64
+ exports._isAtomicEnabled = _isAtomicEnabled;
65
+ const fs = __importStar(require("fs"));
66
+ const path = __importStar(require("path"));
67
+ const ATOMIC_FLAG_ENV = 'OPENLIFE_ATOMIC_WRITES';
68
+ function atomicEnabled() {
69
+ const v = (process.env[ATOMIC_FLAG_ENV] || 'on').toLowerCase();
70
+ return v !== 'off' && v !== '0' && v !== 'false';
71
+ }
72
+ function tempPath(filePath) {
73
+ const rand = Math.random().toString(36).slice(2, 8);
74
+ return `${filePath}.tmp.${process.pid}.${Date.now()}.${rand}`;
75
+ }
76
+ function fsyncFile(p) {
77
+ // writeFileSync does NOT fsync — we must open + fsync + close ourselves
78
+ // so the rename below sees a durable file on disk.
79
+ const fd = fs.openSync(p, 'r+');
80
+ try {
81
+ fs.fsyncSync(fd);
82
+ }
83
+ finally {
84
+ fs.closeSync(fd);
85
+ }
86
+ }
87
+ /**
88
+ * Write a JSON-serializable object to `filePath` atomically.
89
+ *
90
+ * Writes pretty-printed JSON (2-space indent) followed by a trailing newline.
91
+ * Parent directory is created recursively if it does not exist.
92
+ */
93
+ function writeJsonAtomic(filePath, obj) {
94
+ const payload = `${JSON.stringify(obj, null, 2)}\n`;
95
+ writeStringAtomic(filePath, payload);
96
+ }
97
+ /**
98
+ * Write a raw string to `filePath` atomically. Used by writeJsonAtomic
99
+ * internally; exported for callers that need control over serialization
100
+ * (e.g. markdown templates).
101
+ */
102
+ function writeStringAtomic(filePath, content) {
103
+ const dir = path.dirname(filePath);
104
+ if (!fs.existsSync(dir)) {
105
+ fs.mkdirSync(dir, { recursive: true });
106
+ }
107
+ if (!atomicEnabled()) {
108
+ fs.writeFileSync(filePath, content, 'utf-8');
109
+ return;
110
+ }
111
+ const tmp = tempPath(filePath);
112
+ try {
113
+ fs.writeFileSync(tmp, content, 'utf-8');
114
+ fsyncFile(tmp);
115
+ fs.renameSync(tmp, filePath);
116
+ }
117
+ catch (err) {
118
+ // Best-effort cleanup; ignore failures here, the original error is what matters
119
+ try {
120
+ if (fs.existsSync(tmp))
121
+ fs.unlinkSync(tmp);
122
+ }
123
+ catch {
124
+ /* swallow */
125
+ }
126
+ throw err;
127
+ }
128
+ }
129
+ /**
130
+ * Append one JSON object as a single line to a JSONL event log,
131
+ * atomically with respect to crash.
132
+ *
133
+ * Implementation reads the existing file into memory, appends the new line,
134
+ * and rewrites the whole file via the atomic temp+rename dance. This is
135
+ * O(n) per append; suitable for event logs that stay under a few MB
136
+ * (the typical case for `.openlife/*.jsonl` and `.artifacts/**\/events/*.jsonl`).
137
+ *
138
+ * For high-volume logs this becomes expensive; consider sharding or a
139
+ * dedicated append-with-lock implementation if hot paths emerge.
140
+ */
141
+ function appendJsonlAtomic(filePath, obj) {
142
+ const line = `${JSON.stringify(obj)}\n`;
143
+ if (!atomicEnabled()) {
144
+ const dir = path.dirname(filePath);
145
+ if (!fs.existsSync(dir))
146
+ fs.mkdirSync(dir, { recursive: true });
147
+ fs.appendFileSync(filePath, line, 'utf-8');
148
+ return;
149
+ }
150
+ const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
151
+ // Ensure existing content ends with a newline boundary before appending,
152
+ // so a previously truncated final line does not merge with our new entry.
153
+ const sep = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
154
+ writeStringAtomic(filePath, `${existing}${sep}${line}`);
155
+ }
156
+ /**
157
+ * Append a raw string (already-terminated line, no JSON wrapping) atomically.
158
+ * Used by callers that already control their own serialization format.
159
+ */
160
+ function appendStringAtomic(filePath, line) {
161
+ if (!atomicEnabled()) {
162
+ const dir = path.dirname(filePath);
163
+ if (!fs.existsSync(dir))
164
+ fs.mkdirSync(dir, { recursive: true });
165
+ fs.appendFileSync(filePath, line, 'utf-8');
166
+ return;
167
+ }
168
+ const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
169
+ writeStringAtomic(filePath, `${existing}${line}`);
170
+ }
171
+ /**
172
+ * Remove orphaned `.tmp.<pid>.<ts>.<rand>` files older than `olderThanMs`.
173
+ * Returns the count of files removed.
174
+ *
175
+ * Use during boot to clean up after a previous crash that left temp files
176
+ * lingering. Safe to call even when atomic writes are disabled — it only
177
+ * targets the `.tmp.<pid>.*` naming convention we control.
178
+ */
179
+ function purgeStaleTempFiles(dir, olderThanMs) {
180
+ if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory())
181
+ return 0;
182
+ const cutoff = Date.now() - olderThanMs;
183
+ let removed = 0;
184
+ for (const entry of fs.readdirSync(dir)) {
185
+ if (!/\.tmp\.\d+\.\d+\.[a-z0-9]+$/i.test(entry))
186
+ continue;
187
+ const full = path.join(dir, entry);
188
+ try {
189
+ const st = fs.statSync(full);
190
+ if (st.mtimeMs < cutoff) {
191
+ fs.unlinkSync(full);
192
+ removed += 1;
193
+ }
194
+ }
195
+ catch {
196
+ /* race: file deleted by another process — ignore */
197
+ }
198
+ }
199
+ return removed;
200
+ }
201
+ /** Internal — exposed for tests so they can assert the flag wiring. */
202
+ function _isAtomicEnabled() {
203
+ return atomicEnabled();
204
+ }
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ /**
3
+ * DistributedLock — file-based cross-process lock with TTL + heartbeat.
4
+ *
5
+ * Story 6.4 — OpenLife v1.2 Royal Stack.
6
+ *
7
+ * Use case: prevent two OpenLife instances (e.g. dev + autonomous
8
+ * daemon) from running the same WorkflowEngine run or mission
9
+ * concurrently. The lock is a file under `<stateDir>/locks/<key>.lock`
10
+ * containing `{pid, host, lockId, ts, ttlMs}`. Crash safety: if the
11
+ * holder dies, the next contender sees a stale `ts` and can take over
12
+ * after `ttlMs` elapses (no manual unlock needed).
13
+ *
14
+ * Atomicity: lock creation uses `O_EXCL | O_CREAT` so two processes
15
+ * racing for the same key see exactly one winner. AtomicWriter is used
16
+ * for renewals.
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.DistributedLock = void 0;
53
+ const crypto = __importStar(require("crypto"));
54
+ const fs = __importStar(require("fs"));
55
+ const os = __importStar(require("os"));
56
+ const path = __importStar(require("path"));
57
+ const AtomicWriter_1 = require("./AtomicWriter");
58
+ class DistributedLock {
59
+ baseDir;
60
+ /** In-process registry of held locks, keyed by lockId. */
61
+ heldByLockId = new Map();
62
+ constructor(opts = {}) {
63
+ this.baseDir = opts.baseDir
64
+ || path.join(process.env.OPENLIFE_STATE_DIR || path.join(process.cwd(), '.openlife'), 'locks');
65
+ }
66
+ /**
67
+ * Attempt to acquire the lock for `key`. Succeeds if (a) no lock file
68
+ * exists, or (b) the existing lock has expired (ts + ttlMs <= now).
69
+ *
70
+ * If `startHeartbeat: true` (default true), the caller's lock TTL is
71
+ * auto-renewed at ttlMs/3 intervals via setInterval. Call release()
72
+ * to stop the heartbeat.
73
+ */
74
+ acquire(key, ttlMs, opts = {}) {
75
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0) {
76
+ return { ok: false, error: 'io_error', message: 'ttlMs must be a positive number' };
77
+ }
78
+ this.ensureBaseDir();
79
+ const filePath = this.lockPath(key);
80
+ const lockId = this.newLockId();
81
+ const now = Date.now();
82
+ const record = {
83
+ pid: process.pid,
84
+ host: os.hostname(),
85
+ lockId,
86
+ key,
87
+ acquiredAt: now,
88
+ ts: now,
89
+ ttlMs,
90
+ };
91
+ // First attempt: exclusive create
92
+ try {
93
+ const fd = fs.openSync(filePath, 'wx');
94
+ try {
95
+ fs.writeFileSync(fd, JSON.stringify(record, null, 2), 'utf-8');
96
+ }
97
+ finally {
98
+ fs.closeSync(fd);
99
+ }
100
+ this.trackHeld(lockId, filePath, ttlMs, opts.startHeartbeat !== false);
101
+ return { ok: true, lockId, filePath };
102
+ }
103
+ catch (err) {
104
+ const code = err.code;
105
+ if (code !== 'EEXIST') {
106
+ return { ok: false, error: 'io_error', message: err instanceof Error ? err.message : String(err) };
107
+ }
108
+ // Lock file exists — check if it's expired
109
+ }
110
+ // Second attempt: takeover if existing lock is stale
111
+ const existing = this.readLock(filePath);
112
+ if (existing && now - existing.ts > existing.ttlMs) {
113
+ // Expired — overwrite atomically with our record
114
+ (0, AtomicWriter_1.writeJsonAtomic)(filePath, record);
115
+ this.trackHeld(lockId, filePath, ttlMs, opts.startHeartbeat !== false);
116
+ return { ok: true, lockId, filePath };
117
+ }
118
+ return { ok: false, error: 'collision', heldBy: existing ?? undefined };
119
+ }
120
+ /**
121
+ * Update the heartbeat (ts field) on a lock we hold. Returns true if
122
+ * the renewal succeeded (file still exists and our lockId is intact),
123
+ * false if the lock was stolen or removed.
124
+ */
125
+ renew(lockId) {
126
+ const tracked = this.heldByLockId.get(lockId);
127
+ if (!tracked)
128
+ return false;
129
+ const existing = this.readLock(tracked.filePath);
130
+ if (!existing || existing.lockId !== lockId) {
131
+ // Lock was stolen or removed — stop our heartbeat
132
+ this.stopHeartbeat(lockId);
133
+ return false;
134
+ }
135
+ existing.ts = Date.now();
136
+ try {
137
+ (0, AtomicWriter_1.writeJsonAtomic)(tracked.filePath, existing);
138
+ return true;
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ /**
145
+ * Release the lock we hold. Removes the lock file (if we still own it)
146
+ * and stops the heartbeat. Idempotent.
147
+ */
148
+ release(lockId) {
149
+ const tracked = this.heldByLockId.get(lockId);
150
+ if (!tracked)
151
+ return;
152
+ this.stopHeartbeat(lockId);
153
+ const existing = this.readLock(tracked.filePath);
154
+ if (existing && existing.lockId === lockId) {
155
+ try {
156
+ fs.unlinkSync(tracked.filePath);
157
+ }
158
+ catch { /* race or already gone */ }
159
+ }
160
+ this.heldByLockId.delete(lockId);
161
+ }
162
+ /**
163
+ * Inspect the current holder for `key` (or null if unlocked).
164
+ */
165
+ peek(key) {
166
+ return this.readLock(this.lockPath(key));
167
+ }
168
+ /**
169
+ * Release all locks currently held by this process. Useful for clean
170
+ * shutdown of a daemon.
171
+ */
172
+ releaseAll() {
173
+ for (const lockId of Array.from(this.heldByLockId.keys())) {
174
+ this.release(lockId);
175
+ }
176
+ }
177
+ // ─────────────────────────────────────────────────────────
178
+ // Internals
179
+ // ─────────────────────────────────────────────────────────
180
+ trackHeld(lockId, filePath, ttlMs, startHeartbeat) {
181
+ let heartbeat = null;
182
+ if (startHeartbeat) {
183
+ const interval = Math.max(50, Math.floor(ttlMs / 3));
184
+ heartbeat = setInterval(() => {
185
+ this.renew(lockId);
186
+ }, interval);
187
+ // Don't keep the process alive just for the heartbeat
188
+ if (typeof heartbeat.unref === 'function')
189
+ heartbeat.unref();
190
+ }
191
+ this.heldByLockId.set(lockId, { filePath, heartbeat });
192
+ }
193
+ stopHeartbeat(lockId) {
194
+ const tracked = this.heldByLockId.get(lockId);
195
+ if (tracked?.heartbeat) {
196
+ clearInterval(tracked.heartbeat);
197
+ tracked.heartbeat = null;
198
+ }
199
+ }
200
+ readLock(filePath) {
201
+ if (!fs.existsSync(filePath))
202
+ return null;
203
+ try {
204
+ const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
205
+ if (typeof raw?.lockId === 'string' && typeof raw?.ts === 'number')
206
+ return raw;
207
+ return null;
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ }
213
+ ensureBaseDir() {
214
+ if (!fs.existsSync(this.baseDir)) {
215
+ fs.mkdirSync(this.baseDir, { recursive: true });
216
+ }
217
+ }
218
+ lockPath(key) {
219
+ return path.join(this.baseDir, `${this.sanitize(key)}.lock`);
220
+ }
221
+ sanitize(key) {
222
+ return key.replace(/[^a-zA-Z0-9._-]/g, '_');
223
+ }
224
+ newLockId() {
225
+ return `${process.pid}-${Date.now().toString(36)}-${crypto.randomBytes(4).toString('hex')}`;
226
+ }
227
+ /** Exposed for tests so they can assert resolved storage location. */
228
+ _baseDir() {
229
+ return this.baseDir;
230
+ }
231
+ }
232
+ exports.DistributedLock = DistributedLock;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * TemplateRenderer — minimalist {{VAR}} substitution.
4
+ *
5
+ * Story 5.1 — OpenLife v1.2 Royal Stack.
6
+ *
7
+ * Zero external dependencies. Replaces `{{VAR}}` tokens with literal
8
+ * string values from a flat object. Unknown variables are left in place
9
+ * (so missing vars are visible in output rather than silently empty).
10
+ *
11
+ * NOT a templating engine — no conditionals, loops, or HTML escaping.
12
+ * If those become needed in v1.3, swap to Handlebars at this same
13
+ * surface.
14
+ *
15
+ * Use case: SquadCreator / SkillCreator render `dist-templates/{squad,
16
+ * skill}-template/` markdown files with operator-supplied values.
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.renderTemplate = renderTemplate;
53
+ exports.renderTemplateFile = renderTemplateFile;
54
+ exports.listTemplateVars = listTemplateVars;
55
+ const fs = __importStar(require("fs"));
56
+ /**
57
+ * Render a template string by substituting `{{VAR}}` tokens. Unknown
58
+ * tokens are returned verbatim (intentional — surfaces missing vars).
59
+ */
60
+ function renderTemplate(template, vars) {
61
+ return template.replace(/\{\{([A-Z_][A-Z0-9_]*)\}\}/g, (match, name) => {
62
+ return Object.prototype.hasOwnProperty.call(vars, name) ? vars[name] : match;
63
+ });
64
+ }
65
+ /**
66
+ * Render a template file from disk. Throws if the source file does not
67
+ * exist (caller is expected to verify dist-templates layout up-front).
68
+ */
69
+ function renderTemplateFile(filePath, vars) {
70
+ if (!fs.existsSync(filePath)) {
71
+ throw new Error(`template not found: ${filePath}`);
72
+ }
73
+ return renderTemplate(fs.readFileSync(filePath, 'utf-8'), vars);
74
+ }
75
+ /**
76
+ * Inspect a template for required variables — returns the sorted list of
77
+ * unique `{{VAR}}` tokens. Useful for tooling that wants to surface
78
+ * "missing required variables" before render.
79
+ */
80
+ function listTemplateVars(template) {
81
+ const found = new Set();
82
+ template.replace(/\{\{([A-Z_][A-Z0-9_]*)\}\}/g, (_, name) => {
83
+ found.add(name);
84
+ return '';
85
+ });
86
+ return Array.from(found).sort();
87
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * WatchdogHeartbeat — periodic liveness signal for external supervisors.
4
+ *
5
+ * Story 6.6 — OpenLife v1.2 Royal Stack.
6
+ *
7
+ * The daemon emits a heartbeat file every `intervalMs` so an external
8
+ * supervisor (systemd `WatchdogSec=`, supervisord `eventlistener`, k8s
9
+ * livenessProbe via a file mtime check) can detect hangs even when the
10
+ * HTTP `/health` endpoint becomes unresponsive (e.g. event-loop block).
11
+ *
12
+ * Format: `.openlife/heartbeat.json` with `{ pid, host, ts, uptime_s,
13
+ * startedAt }`. ts is updated atomically each tick so a torn read is
14
+ * impossible.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.WatchdogHeartbeat = void 0;
51
+ const os = __importStar(require("os"));
52
+ const path = __importStar(require("path"));
53
+ const AtomicWriter_1 = require("./AtomicWriter");
54
+ class WatchdogHeartbeat {
55
+ filePath;
56
+ intervalMs;
57
+ startedAt;
58
+ version;
59
+ timer = null;
60
+ constructor(opts = {}) {
61
+ const stateDir = process.env.OPENLIFE_STATE_DIR || path.join(process.cwd(), '.openlife');
62
+ this.filePath = opts.filePath || path.join(stateDir, 'heartbeat.json');
63
+ this.intervalMs = opts.intervalMs ?? 30_000;
64
+ this.startedAt = Date.now();
65
+ this.version = opts.version;
66
+ }
67
+ /**
68
+ * Emit one heartbeat immediately and schedule periodic re-emission.
69
+ * Idempotent: calling start() while already running is a no-op.
70
+ */
71
+ start() {
72
+ if (this.timer)
73
+ return;
74
+ this.emit(); // immediate tick so external supervisor sees freshness on boot
75
+ this.timer = setInterval(() => {
76
+ try {
77
+ this.emit();
78
+ }
79
+ catch { /* swallow — best-effort writes */ }
80
+ }, this.intervalMs);
81
+ if (typeof this.timer.unref === 'function')
82
+ this.timer.unref();
83
+ }
84
+ /**
85
+ * Stop emitting heartbeats. Idempotent. Does not delete the heartbeat
86
+ * file (so post-shutdown the supervisor still sees the last known
87
+ * good ts; staleness is the supervisor's signal that we are down).
88
+ */
89
+ stop() {
90
+ if (this.timer) {
91
+ clearInterval(this.timer);
92
+ this.timer = null;
93
+ }
94
+ }
95
+ /**
96
+ * Force-emit one heartbeat now (used by tests and graceful shutdown).
97
+ */
98
+ emit() {
99
+ const now = Date.now();
100
+ const rec = {
101
+ pid: process.pid,
102
+ host: os.hostname(),
103
+ ts: now,
104
+ uptime_s: Math.floor((now - this.startedAt) / 1000),
105
+ startedAt: this.startedAt,
106
+ version: this.version,
107
+ };
108
+ (0, AtomicWriter_1.writeJsonAtomic)(this.filePath, rec);
109
+ return rec;
110
+ }
111
+ /** Exposed for tests. */
112
+ _filePath() {
113
+ return this.filePath;
114
+ }
115
+ }
116
+ exports.WatchdogHeartbeat = WatchdogHeartbeat;